#!/usr/bin/perl
#!/usr/bin/sh
##########initialization#####################
use strict;
use warnings;
use POSIX;
use Fcntl qw(:flock :seek)
  ;    #Export fileLock and seek  opened file using quote word qw
use Switch;

#use Cwd;    # current working directory
my $path = getcwd;    # current working directory
print "current working path = $path\n";
my $pwd;
my @dirstruct;

#use Math::Complex;
use List::Util qw[min max];
##############################################################################
###############################SetUp Environmental Variables#########################################
$ENV{'PATH'} =
'/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/Xilinx/12.4/ISE_DS/ISE/bin/lin64:';
$ENV{'XILINXD_LICENSE_FILE'} = '2100@localhost';

#$ENV{'LD_PRELOAD'}=':/opt/Xilinx/12.4/ISE_DS/ISE/lib/lin64/libXst_CoreData.so:/opt/Xilinx/12.4/ISE_DS/ISE/lib/lin64/libXst_Core.so:/opt/Xilinx/12.4/ISE_DS/ISE/lib/lin64/libTw.so:/opt/Xilinx/12.4/ISE_DS/ISE/lib/lin64/libTw_DelayCache.so:';
#system("echo \$XILINXD_LICENSE_FILE");
#$ENV{'PATH'} =
#'/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/shaon/Xilinx92i/bin/lin:';
#################################################################################################
clean_up();    #cleanup project files

#use Shell::Source;
#my $env_path= Shell::Source->new(shell=>"sh",file=>"./12_4_xilinx.sh");
#my $env_path= Shell::Source->new (shell=>"sh", file=> "./12_4_xilinx.sh", run => "source -f -c [[file]]");
#$env_path->inherit;
#system("xst -ifn top.script -intstyle ise");
#*********************subroutine to reset to current directory path
sub reset_dir {
	chdir("$path") || die "Error!! Could not change Directory.";
}

#****************************************************end subroutine**************
#system("xst");
#my $source= Shell::Source->new (shell=>"sh", file=> "./12_4_xilinx.sh");
#$source->inherit;
#system("xst");
print "\nPR Automation Start:\n";
print "Please make sure there are no HDL syntax errors before running tool\n";
print "NOTE: Tool in Development Phase\n\n";
############Determine if ucf file is generated from DAPR itself or User Provided######################
my $DAPR_flag_ucf = 0;

#print ("\n$time_data\n");
my $ucf_flag = 1;    #check if ucf file is provided
open( INF_ucf, "<top.ucf" ) or print "No UCF FILE found\n" and $ucf_flag = 0;
if ( $ucf_flag == 1 ) {
	foreach my $ucf_line (<INF_ucf>) {
		if ( $ucf_line =~ /DAPR/i ) {
			$DAPR_flag_ucf = 1;    #ucf file created by DAPR
			last;
		}
	}
	close(INF_ucf);
}
############Create PR report information file######################
open( report_file, ">report_file.log" )
  or die "Cannot open output file!";
my $start_time = localtime(time);
print report_file
"PR automation information file: Start time: $start_time\n------------------------------------------------------\n";
#################TEST ZONE#################
# my $line = "Number of error messages: 0";
#print ("\nXXXXXXX $line XXXXXXXXX\n");
#$line=~s/(\D+)//g;
#print ("\nXXXXXXX $line XXXXXXXXX\n");
##########################################Global PR Variable Declarations for File Parsing##########################
my @filelist;    #array of all file names
##component parsing variables##
my @component_name_list;    #array of all design components
my $component_count = 0;    #total number of components in the design
my $component_flag  = 0;
my @component_port_list
  ;    #contains the name of all ports in the component...this is redundant
my @component_in_signal_list
  ;    # contains all the component input port names in the design
my @component_in_signal_width;    # contains the size of input component ports
my @component_out_signal_list
  ;    # contains all the component output port names in the design
my @component_out_signal_width;    # contains the size of ouput component ports
my @component_in_signal_count
  ;    ### counts the number of input signals in the current component
my @component_out_signal_count
  ;    ### counts the number of ouput signals in the current component
my $PR_flag           = 0;
my $Top_flag          = 0;
my $Base_flag         = 0;
my $Base_region_count = 0;
my $PR_flag_syn       = 0;
my $PR_region_count   = 0;
my @PR_file_list;
my @PR_file_list_ngc;
my @PR_module_list;
my @PR_component_list;
my @PR_port_count;
my @PR_port_list;
my @PR_module_count;
my @PR_signal_list;
my @PR_signal_widths;
my @Base_file_list;
my @Base_module_list;
my @Base_component_list;
my @Base_port_count;
my @Base_port_list;
my @Base_signal_list;
my @Base_signal_widths;
my @Top_in_signal_list;
my @Top_out_signal_list;
my $Top_clock_signal_name;
my @Top_in_signal_width_string;
my @Top_out_signal_width_string;
my $Top_entity_list;
my $infile;
my $line;
my $string1;
my $string2;
my @module_list;
my @module_slice_requirement;
my @region_list;
my @region_instance;
my $DCM_flag     = 0;
my $DCM_count    = 0;
my $DCM_clk_flag = 0;
my @DCM_inst_list;
my @DCM_port_count;
my @DCM_signal_list;
my $BUFG_flag  = 0;
my $BUFG_count = 0;
my @BUFG_inst_list;
my $IBUFG_clk_flag = 0;
my $IBUFG_flag     = 0;
my $IBUFG_I;
my $IBUFG_O;
my @signal_name_list;
my @signal_width_string;
my @max_slice_reqs = 0;
our @module_list_fp;

#my $threshold = 0;    #floorplanner threshold value for increasing slice range
#my $int_frag    = 10;   #floorplanner threshold value for increasing slice range
#my $int_frag_x  = 1;    #floorplanner threshold value for increasing slice range
#my $int_frag_y  = 1;    #floorplanner threshold value for increasing slice range
#my $white_space = 1;    #0% whitespace allocated
######################Check if input Command line Argument is Given#############################################################
#if ( !$ARGV[0] )
#{
#	print "Please enter top file name:";
#	$infile = <STDIN>;
#	$infile =~ s/\s+//g;
#	chomp($infile);
#	while ( !( $infile =~ /^([-\@\w.]+)$/ ) )
#	{
#		print "Invalid File Name!\nPlease enter top file name:";
#		$infile = <STDIN>;
#		$infile =~ s/\s+//g;
#		chomp($infile);
#	}
#} else
#{
#	$infile = $ARGV[0];
#	chomp($infile);
#}
######################Check for device type######################################################
my $device_name = "xc4vlx25-10ff668";

#	my $device_name;
#	my $choice;
#	my $V4fx12  = "xc4vfx12-10ff668";
#	my $V4lx25  = "xc4vlx25-10ff668";
#	my $V4lx100 = "xc4vlx100-10ff1148";
#	if ( !$ARGV[1] )
#	{
#		print "Please choose a Device\n";
#		print "1:$V4fx12\n2:$V4lx25\n3:$V4lx100\n";
#		$choice = <STDIN>;
#		$choice =~ s/\s+//g;
#		chomp($choice);
#		if ( $choice eq "1" )
#		{
#			$device_name = $V4fx12;
#		} elsif ( $choice eq "2" )
#		{
#			$device_name = $V4lx25;
#		} elsif ( $choice eq "3" )
#		{
#			$device_name = $V4lx100;
#		} else
#		{
#			print
#"Invalid Choice! Please enter the digit in front of the device name\n";
#			device_name();
#		}
#		chomp($device_name);
#	} else
#	{
#		my $choice = $ARGV[1];
#		$choice =~ s/\s+//g;
#		chomp($choice);
#		if ( $choice eq $V4fx12 )
#		{
#			$device_name = $V4fx12;
#		} elsif ( $choice eq $V4lx25 )
#		{
#			$device_name = $V4lx25;
#		} elsif ( $choice eq $V4lx100 )
#		{
#			$device_name = $V4lx100;
#		} else
#		{
#			print "Invalid device name!\n";
#			$ARGV[1] = "";
#			device_name();
#		}
#		chomp($device_name);
#	}
################Beginning of Top file scanning for Top, Base and PR region/Module indentification###############
#my @infile = split( '\.', $infile )
;    # split "." if arg = top.vhd is given or not is arg is only top

#my $infilename = $infile[0];
my $infilename = "top";
push( @filelist, $infilename );
open( INFILE, "<$infilename.vhd" )
  or die
"$infilename.vhd VHDL file cannot be opened! It doesn't exist!\nArgument format is top file name followed by device type.\nExample: top.vhd xc4vlx15-10ff668\n";
flock( INFILE, LOCK_SH );
foreach my $line (<INFILE>) {
	chomp($line);    #remove newlines
	if ( !$line ) {

		#print "line is empty\n";
		next;
	}
	my $string = $line;
	$string =~ s/\s+//g;    #remove spaces

# need to fix entire parser according to syntax trees. parser does not handle newline properly.
#Parsing the component input and output port lists for the components***************************************************************************
#ignore and remove comments other than --PRR_begin, --static_begin and --Top_begin
	if ( $string =~ /--+/i ) {

		#print "comments = $string\n";
		if (    ( $string !~ /--PRR_begin/i )
			 && ( $string !~ /--PRR_end/i )
			 && ( $string !~ /--static_begin/i )
			 && ( $string !~ /--static_end/i )
			 && ( $string !~ /--Top_begin/i )
			 && ( $string !~ /--Top_end/i )
			 && ( $string !~ /--clk/i ) )
		{
			#print "comments2 = $string\n";
			my @temp_string = split( '--', $string );

			#		print "string = $string\n";
			#		print "temp_string = $temp_string[0]\n";
			#		print "temp_string = @temp_string\n";
			next if ( !$temp_string[0] );
			$string = $temp_string[0];
		}

		#			{
		#				if($string eq "") {
		#
		#				print "string is empty\n";
		#				next;
		#				}
		#			}
		#		print "after removing comments = $string\n";'
	}
	if ( $string =~ /--PRR_begin/i ) {
		$PR_flag     = 1;
		$PR_flag_syn = 1;
		$PR_region_count++;
		print report_file
"PR Region(s) found\n------------------------------------------------------\n\n$PR_region_count",
		  "st Region Code shown below:\n\n";
		my @temp_string2 = split( '::', $string );

		#	print("\ntemp_string2 = @temp_string2\n");
		my @temp_string3 = split( ',', $temp_string2[1] );    #store PRR modules
		push( @PR_file_list, @temp_string3 );
		$PR_module_count[ $PR_region_count - 1 ] = @temp_string3;
		push( @filelist, @temp_string3 );
		my @temp_string4 =
		  split( ',', $temp_string2[2] );    #store PRR entity name
		push( @PR_file_list_ngc, @temp_string4 );

		#	print("filelist = @filelist\n");
		#	print("PR_file_list = @PR_file_list\n");
		#	print("PR_file_list_ngc = @PR_file_list_ngc\n");
		print report_file "Entering PR region Code\n";
		next;
	}
	elsif ( $string =~ /--static_begin/i ) {
		$Base_region_count++;
		$Base_flag = 1;
		$string    = $line;
		$string =~ s/\s+//g;
		my @temp_string3 = split( '::', $string );
		push( @Base_file_list, $temp_string3[1] );
		push( @filelist,       $temp_string3[1] );

		#		print report_file "Entering Static region Code\n";
		next;
	}
	elsif ( $string =~ /--Top_begin/i ) {
		$Top_flag = 1;
		next;

		#		print report_file "Entering Top region Code\n";
	}
	elsif ( $string =~ /^component/i ) {

		#$string =~ s/\s+//g;
		my @temp_string = split( /component/i, $string );
		$temp_string[1] =~ s/is$//;

		#my @temp_string2 = split( /is/i, $temp_string[1] );
		#$string = $temp_string2[0];
		#print "$string\n";
		#print "$temp_string[1]\n";
		push( @component_name_list, $temp_string[1] );
		$component_flag = 1;
		$component_count++;
		next;
	}
	elsif ( $string =~ /^signal/i ) {
		$string =~ /(\w+):(\w+)/;
		my $temp_string1 = $1;
		my $temp_string2 = $2;
		$temp_string1 =~ s/signal//g
		  ;    # substitute signal with nothing i.e. remove the word signal
		push( @signal_name_list, $temp_string1 );
		my @temp_string = split( /\W/, $string );

		#print "@temp_string\n";
		if ( !$temp_string[2] )
		{      #puts width of signal equals 1 if it is not std_logic_vector
			push( @signal_width_string, "1" );
		}
		else {
			my @temp_string3;
			if ( $temp_string[2] =~ /downto/i ) {
				@temp_string3 = split( /downto/i, $temp_string[2] );
				$temp_string3[2] = $temp_string3[0] - $temp_string3[1] + 1;
			}
			else {
				@temp_string3 = split( /upto/i, $temp_string[2] );
				$temp_string3[2] = $temp_string3[0] - $temp_string3[1] + 1;
			}

			#print "$temp_string3[2]\n";
			push( @signal_width_string, $temp_string3[2] );
		}
		next;
	}

	# Parses out information inside the declarations according to flags
	if ( $component_flag == 1 ) {
		$string = $line;
		$string =~ s/\s+//g;
		###Detects component declaration end###
		if ( $string =~ m/endcomponent/i )    # Exits current component parsing
		{
			#print" xxx\n";
			$component_flag = 0;
			next;
		}

		#Starts parsing inside component###
		if ( $line =~ /:/i ) {
			$string =~ /(\w+):(\w+)/;         #split component names
			my $temp_string1 = $1;
			my $temp_string2 = $2;
			push( @component_port_list, $temp_string1 );    #redundant
			#####contains information the port, i.e, size,type etc####
			if ( $temp_string2 =~ /in+/i ) {    # parsing input variables
				$component_in_signal_count[ $component_count -
				  1 ]++
				  ; ### counts the number of input signals in the current component
				push( @component_in_signal_list, $temp_string1 );
				my @temp_string = split( /\W/, $string );
				if ( !$temp_string[2] )
				{   #puts width of signal equals 1 if it is not std_logic_vector
					push( @component_in_signal_width, "1" );
				}
				else {
					my @temp_string3;
					if ( $temp_string[2] =~ /downto/i ) {
						@temp_string3 = split( /downto/i, $temp_string[2] );
						$temp_string3[2] =
						  $temp_string3[0] - $temp_string3[1] + 1;
					}
					else {
						@temp_string3 = split( /upto/i, $temp_string[2] );
						$temp_string3[2] =
						  $temp_string3[0] - $temp_string3[1] + 1;
					}
					push( @component_in_signal_width, $temp_string3[2] );
				}
				next;
			}
			else {    # parsing output variables
				$component_out_signal_count[ $component_count - 1 ]++;
				push( @component_out_signal_list, $temp_string1 );
				my @temp_string = split( /\W/, $string );
				if ( !$temp_string[2] )
				{   #puts width of signal equals 1 if it is not std_logic_vector
					push( @component_out_signal_width, "1" );
				}
				else {
					my @temp_string3;
					if ( $temp_string[2] =~ /downto/i ) {
						@temp_string3 = split( /downto/i, $temp_string[2] );
						$temp_string3[2] =
						  $temp_string3[0] - $temp_string3[1] + 1;
					}
					else {
						@temp_string3 = split( /upto/i, $temp_string[2] );
						$temp_string3[2] =
						  $temp_string3[0] - $temp_string3[1] + 1;
					}
					push( @component_out_signal_width, $temp_string3[2] );
				}
				next;
			}
		}
	}

	#Check for declared signals and store them in a signal array
	elsif (    ( $PR_flag == 0 )
			&& ( $Base_flag == 0 )
			&& ( $Top_flag == 0 ) )
	{
		next
		  if (    ( $line !~ /--PRR_begin/i )
			   && ( $line !~ /--static_begin/i )
			   && ( $line !~ /--Top_begin/i ) );
	}
	else {
		if (    ( $line =~ /--PRR_end/i )
			 || ( $line =~ /--static_end/i )
			 || ( $line =~ /--Top_end/i ) )
		{
			$PR_flag   = 0;
			$Base_flag = 0;
			$Top_flag  = 0;
			print report_file
			  "\n------------------------------------------------------\n";
			next;
		}
		else {
			if ( ( $line =~ /:/i ) || ( $line =~ /entity/i ) ) {
				$string = $line;
				if ( $PR_flag == 1 ) {
					$string =~ s/\s+//g;
					$string =~ /(\w+):(\w+)/;
					push( @PR_module_list,    $1 );
					push( @PR_component_list, $2 );
				}
				elsif ( $Base_flag == 1 ) {
					$string =~ s/\s+//g;
					$string =~ /(\w+):(\w+)/;
					push( @Base_module_list,    $1 );
					push( @Base_component_list, $2 );
				}
				elsif ( $Top_flag == 1 ) {

					#Parse out top module input and output signals
					if ( $line =~ /:/i ) {
						$string =~ s/\s+//g;
						$string =~ /(\w+):(\w+)/;

						#Doesn't have support for inout signals yet
						my $temp_string1 = $1;
						my $temp_string2 = $2;
						if ( $temp_string2 =~ /in+/i )
						{    # parsing input variables
							push( @Top_in_signal_list, $temp_string1 );
							my @temp_string = split( /\W/, $string );
							if ( $string =~ /--clk/ ) {
								$Top_clock_signal_name = $temp_string1;
							}
							if ( !$temp_string[2] )
							{ #puts width of signal equals 1 if it is not std_logic_vector
								push( @Top_in_signal_width_string, "1" );
							}
							else {
								my @temp_string3;
								if ( $temp_string[2] =~ /downto/i ) {
									@temp_string3 =
									  split( /downto/i, $temp_string[2] );
									$temp_string3[2] =
									  $temp_string3[0] - $temp_string3[1] + 1;
								}
								else {
									@temp_string3 =
									  split( /upto/i, $temp_string[2] );
									$temp_string3[2] =
									  $temp_string3[0] - $temp_string3[1] + 1;
								}
								push( @Top_in_signal_width_string,
									  $temp_string3[2] );
							}
						}
						else {    # parsing output variables
							push( @Top_out_signal_list, $temp_string1 );
							my @temp_string = split( /\W/, $string );
							if ( !$temp_string[2] )
							{ #puts width of signal equals 1 if it is not std_logic_vector
								push( @Top_in_signal_width_string, "1" );
							}
							else {
								my @temp_string3;
								if ( $temp_string[2] =~ /downto/i ) {
									@temp_string3 =
									  split( /downto/i, $temp_string[2] );
									$temp_string3[2] =
									  $temp_string3[0] - $temp_string3[1] + 1;
								}
								else {
									@temp_string3 =
									  split( /upto/i, $temp_string[2] );
									$temp_string3[2] =
									  $temp_string3[0] - $temp_string3[1] + 1;
								}
								push( @Top_out_signal_width_string,
									  $temp_string3[2] );
							}
						}

						#Parse out top module input and output signals
					}

					#Parse out top entity name file name
					elsif ( $line =~ /entity/i ) {
						my @temp_string1 = split( ' ', $string );
						$Top_entity_list = $temp_string1[1];
					}
				}
			}

			#Parse out PR, Base Port Map
			elsif ( $line =~ /=>/i ) {
				$string = $line;
				$string =~ s/\s+//g;

				#$string =~ /(\w+)=>(\w+)/;
				my @temp_string = split( '=>', $string );
				if ( $PR_flag == 1 ) {

					#	$temp_string[1] =~ s/,//g; #gets rid of comma at the end
					my @temp_string2 = split( /\W/, $temp_string[1] )
					  ; #splits to check if signal is connected as specific bus list e.g clk[5]

					#print  "temp_string2 = $temp_string2[1]\n";
					#	print "temp_string = $temp_string[1]\n";
					if ( !$temp_string2[1] && $temp_string[1] !~ /0/ )
					{    # checks for width of connections
						my $i = 0;
						foreach my $compare (@signal_name_list) {
							if ( $compare eq $temp_string2[0] ) {
								push( @PR_signal_widths,
									  $signal_width_string[$i] );
							}
							$i++;
						}
					}
					elsif ( $temp_string2[1] =~ /\D+/i ) {
						my @temp_string3;
						if ( $temp_string2[1] =~ /downto/i ) {
							@temp_string3 =
							  split( /downto/i, $temp_string2[1] );
							$temp_string3[2] =
							  $temp_string3[0] - $temp_string3[1] + 1;
						}
						push( @PR_signal_widths, $temp_string3[2] );
					}
					else {
						push( @PR_signal_widths, "1" );
					}
					$PR_port_count[ $PR_region_count - 1 ]++;
					push( @PR_port_list,   $temp_string[0] );
					push( @PR_signal_list, $temp_string2[0] );
				}
				elsif ( $Base_flag == 1 ) {
					my @temp_string2 = split( /\W/, $temp_string[1] );

					#print "temp_string = @temp_string";
					if ( !$temp_string2[1] && $temp_string[1] !~ /0/ )
					{    # checks for width of connections
						my $i = 0;
						foreach my $compare (@signal_name_list) {
							if ( $compare eq $temp_string2[0] ) {
								push( @Base_signal_widths,
									  $signal_width_string[$i] );
							}
							$i++;
						}
					}
					elsif ( $temp_string2[1] =~ /\D+/i ) {
						my @temp_string3;
						if ( $temp_string2[1] =~ /downto/i ) {
							@temp_string3 =
							  split( /downto/i, $temp_string2[1] );
							$temp_string3[2] =
							  $temp_string3[0] - $temp_string3[1] + 1;
						}
						push( @Base_signal_widths, $temp_string3[2] );
					}
					else {
						push( @Base_signal_widths, "1" );
					}
					$Base_port_count[ $Base_region_count - 1 ]++;
					push( @Base_port_list,   $temp_string[0] );
					push( @Base_signal_list, $temp_string2[0] );
				}
			}

			#Parse out PR and Base Port Map Connections
			my @temp_line = split( ' ', $line );

			#	print report_file "@temp_line\n";
		}
	}

#end component port list parsing*************************************************************************************************************
#Top entity, PR region declaration and static region information parsing
}

#close(INFILE);

################################subroutine to print parsed values to report_file###########################################
sub print_R {
	print report_file "Component list: @component_name_list\n";
	print report_file "Component count: $component_count\n";
	print report_file "Component port list: @component_port_list\n";
	print report_file
	  "Component in port count: @component_in_signal_count\n";   # same as below
	print report_file "Component in port list: @component_in_signal_list\n"
	  ;    # should be port count not signal count
	print report_file "Component in port widths: @component_in_signal_width\n"
	  ;    # should be port count not signal count
	print report_file
	  "Component out port count: @component_out_signal_count\n"; # same as above
	print report_file
	  "Component out port list: @component_out_signal_list\n";   # same as above
	print report_file
	  "Component out port widths: @component_out_signal_width\n\n"
	  ;                                                          #same as above
	print report_file "Top Entity List: $Top_entity_list\n";
	print report_file "Top In Signal List: @Top_in_signal_list\n";
	print report_file "Top Out Signal List: @Top_out_signal_list\n";
	print report_file "Top_in_signal_widths : @Top_in_signal_width_string\n";
	print report_file "Top_out_signal_widths : @Top_out_signal_width_string\n";
	print report_file "Top_clock_signal_name : $Top_clock_signal_name\n\n";
	print report_file "Base File list: @Base_file_list\n";
	print report_file "Base Component List: @Base_component_list\n";
	print report_file "Base Region Count: $Base_region_count\n";
	print report_file "Base Module List: @Base_module_list\n";
	print report_file "Base port count: @Base_port_count\n";
	print report_file "Base port List: @Base_port_list\n";
	print report_file "Base Signal List: @Base_signal_list\n";
	print report_file "Base Signal Widths: @Base_signal_widths\n\n";
	print report_file "PR File List: @PR_file_list\n";
	print report_file "PR File List ngc: @PR_file_list_ngc\n";
	print report_file "PR Component List: @PR_component_list\n";
	print report_file "PR Region Count: $PR_region_count\n";
	print report_file "PR Module Count: @PR_module_count\n";
	print report_file "PR Module List: @PR_module_list\n";
	print report_file "PR port count: @PR_port_count\n";
	print report_file "PR Port List: @PR_port_list\n";
	print report_file "PR Signal List: @PR_signal_list\n";
	print report_file "PR Signal Widths: @PR_signal_widths\n\n";
	print report_file "signal_name_list @signal_name_list\n";
	print report_file "signal_width_string @signal_width_string\n\n";
	print report_file "Module List: @module_list\n";
	print report_file "Region List: @region_list\n";
	print report_file "Region instance list: @region_instance\n";
	print report_file "Module Slice Requirement: @module_slice_requirement\n";
	print report_file "Module_list_fp: @module_list_fp\n";
	print report_file "Max_slice_reqs: @max_slice_reqs\n";
}
#################CREATE NECESSARY DATA FILES########################################
open( RESULTS_iter, ">iter.txt" ) or die "results file cannot be created!\n";
open( RESULTS_clk,  ">clk.txt" )  or die "results file cannot be created!\n";

#open(RESULTS_pwr, ">pwr.txt") or die "results file cannot be created!\n";
#open( RESULTS_bs_size, ">bs_size.txt" )
#  or die "results file cannot be created!\n";

#open(RESULTS_PRR_size, ">PRR_size.txt") or die "results file cannot be created!\n";
open( RESULTS_FP, ">ucf_file_list.txt" )
  or die "results file cannot be created!\n";
open( RESULTS_TS, ">time_stamp.txt" )
  or die "results file cannot be created!\n";

open( RESULTS_TS_total, ">time_stamp_total.txt" )
  or die "results file cannot be created!\n";

#open( New_out, ">new_out.txt" ) or die "results file cannot be created!\n";
#open( ES_out,  ">es_out.txt" )  or die "results file cannot be created!\n";
###################################################################################
########################### Design Flow Subroutines #########################
#xst();
#candidate_gen();
##################################CANDIDATE GENERATION################################
######################Candidate generation variables################################
my $time_stamp_date    = localtime(time);
my $time_stamp_seconds = time();
my @time_stamps_date;
my @time_stamps_seconds;
my $time_stamp_total     = 0;
my @new_out_pp_Y_vals    = ();
my @new_out_pp_X_vals    = ();
my @new_in_pp_inst_name  = ();
my @new_out_pp_inst_name = ();
my @design_iteration;
my @clock_frequency_list;
my @partial_bitstream_size;
my @power_list;
my @PRR_size;
my @best_clock_frequency_list;
my $rand_range = 5;
my $rand_iter  = int( rand($rand_range) ) + 5; #A minimum of 5 random iterations
my $iteration  = 1;
my $iteration_max          = 20;
my $iteration_max_constant = $iteration_max;

#my $rand_range=20;
#my $rand_iter= 2;
###################SA Variables#########################
my $Move;
my $T_reduction_rate = 0.85;

my $average_cost     = 0;
my $T_initial        = 0;
my $uphill           = 0;
my $MT               = 0;
my $Reject           = 0;
my $Temperature      = 0;
my $P_accept         = 0.99;
my $SA_flag          = 0;
my $e = exp(1);


my @E0_SA;
my @E_orig;
my @BEST_FP;
my $BEST_FP_ITER;
my $N = 0;

my $best_design_no   = 0;
my $best_clock_frequency;

my @E0;
my @E_stack_fp;
my $module_name;
my $module_slice_reqs;





my @placement_contraints_X_min;
my @placement_contraints_X_max;
my @placement_contraints_Y_min;
my @placement_contraints_Y_max;
my @place_contraints_module;


my $x_min = 0;
my $x_min_global = 0; #this is used to intialize the starting postion of the floorplanner
my $y_min = 0;
my $x_max = 0;
my $x_max_global = 0; # this is used so that adjacent modules dont overlap with slicing floorplanning
my $y_max = 0;
my $y_min_global = 0;
my $x_min_last = 0;
my $y_min_last = 0;
my $x_max_last = 0;
my $y_max_last = 0;

our $total_V_slice_reqs = 0;
our $total_H_slice_reqs = 0;

###################SA Variables#########################
my @initial_in_pp_Y_vals   = ();
my @initial_in_pp_X_vals   = ();
my @initial_out_pp_Y_vals  = ();
my @initial_out_pp_X_vals  = ();
my @best_in_pp_Y_vals      = ();
my @best_in_pp_X_vals      = ();
my @best_out_pp_Y_vals     = ();
my @best_out_pp_X_vals     = ();
my @new_in_pp_Y_vals       = ();
my @new_in_pp_X_vals       = ();
my @accepted_in_pp_Y_vals  = ();
my @accepted_in_pp_X_vals  = ();
my @accepted_out_pp_Y_vals = ();
my @accepted_out_pp_X_vals = ();
my $PAR_error_count        = 0;
my $PAR_error_count_ws     = 0;
my $internal_PAR_Flag      = 0;
my $PAR_error_flag         = 0;

#my $BLD_error_flag =0;
my $MAP_error_count = 0;

#USED in ucf range allocation
my $Y_min;
my $Y_max;
my $X_min;
my $X_max;
my $RAMB16_Y_min;
my $RAMB16_Y_max;
my $RAMB16_X_min;
my $RAMB16_X_max;
my $DSP48_Y_min;
my $DSP48_Y_max;
my $DSP48_X_min;
my $DSP48_X_max;
my $FIFO16_Y_min;
my $FIFO16_Y_max;
my $FIFO16_X_min;
my $FIFO16_X_max;

#USED in ucf range allocation
my $in_pp_inc  = 0;
my $out_pp_inc = 0;
my $flag0      = 0;
my @PRRs;
my @ordered_modules;
my @ordered_module_widths;
my @input_pps;
my @input_pps_count;
my @output_pps;
my @output_pps_count;

#restore starting location in Simulated annealing if placement is a an UPHILL/Bad move

my $old_xmin_global;
my $old_ymin_global;
my $old_xmax_global;
my $old_ymax_global;


xst();
print_R();

my $int_frag    = 10;   #floorplanner threshold value for increasing slice range
my $int_frag_x  = 1;    #floorplanner threshold value for increasing slice range
my $int_frag_y  = 1;    #floorplanner threshold value for increasing slice range
my $white_space = 0;    #0% whitespace allocated


$rand_range = 10;
$rand_iter  = int( rand($rand_range) ) + 5; #A minimum of 5 random iterations

#$rand_iter  = int( rand($rand_range) ); #A minimum of 5 random iterations
$iteration  = 1;
#$rand_iter = 2;
$iteration_max          = 1000;



$MT =1 ;	
	
#while ( $iteration <= $iteration_max or (($Reject/$MT) > 0.95) or ($Temperature <= $e) ) { # use this to run the algorithm till %5 moves are accepted or Temeprature ,i.e, acceptance probality is too low

while ( $iteration <= $iteration_max ) { # begining of SA algorithm
			
	my $temp = $Reject/$MT;
	
	print report_file " Candidate generation for iteration = $iteration, Reject/MT = $temp < 0.95,  Temperature = $Temperature e = $e)";
	candidate_gen();
	
}




###########################################################
sub candidate_gen {

	#####################begin candidate generation loop####################### 
		print
		  "##################Iteration for loop $iteration################\n";
		$time_stamp_date    = localtime(time);
		$time_stamp_seconds = time();
		$time_stamp_total += $time_stamp_seconds;
		print( RESULTS_TS_total "$time_stamp_total\n" );
		push( @time_stamps_date,    $time_stamp_date );
		push( @time_stamps_seconds, $time_stamp_seconds );
		print( RESULTS_TS "$time_stamp_seconds\n" );
		print( report_file
"\nXXXXXXXXXXXXXXXXXiteration_max= $iteration_max, iteration=$iteration Best_design_no. $best_design_no rand_iteration=$rand_iter XXXXXXXXXXXXXXXXXXXX\n"
		);
		mkdir("./PR_Automated/design$iteration")
		  || die "cannot make directory PR_Automated/design$iteration";
		
		
		
		overlay_gen(); # generates library file, random PRR placements and SA based PRR placement
	
		
		
				
###################################################################
#	print(report_file "\nXXXXXXXXXXXXXXXXXiteration_max= $iteration_max, iteration=$iteration XXXXXXXXXXXXXXXXXXXX\n");
	
	
	#######################Output Max clock design number#################
	my $lp_count      = 0;
	my $max_clk       = 0;
	my $design_number = 0;
	foreach (@clock_frequency_list) {
		my $temp_clk = $clock_frequency_list[$lp_count];
		if ( $max_clk < $temp_clk ) {
			$max_clk       = $temp_clk;
			$design_number = $lp_count + 1;
		}
		$lp_count++;
	}
	print report_file
"\nDesign Clock list = @clock_frequency_list \nDesign $design_number has the maximum clock among all designs running at $max_clk\/MHz\n\n";
	print
"\nDesign Clock list = @clock_frequency_list \nDesign $design_number has the maximum clock among all designs running at $max_clk MHz\n\n";
######################End Output Max clock design number#################
}


#######end candidate generation#############################################
####################################OVERLAY GENERATION SUBROUTINE##########################
#**********************Overlay_gen********************************************************************
sub overlay_gen {
	VLX25();    # Create virtex-4 lx25 resource library file
	    #allocate(); #allocate resources in virtex-4 lx25 resource library file

	sub VLX25 {
		system("rm -rf *.dll");
		open( OUT, ">V4LX25.dll" ) or die "Cannot open output file!";
		print OUT (
"####################################### Device Library file #######################################\n###################### LEGEND: S=SLICE, R=RAMB16, F=FIFO16, D=DSP16 ####################################\n############### 1 Prefix means Vacant resource, 0 Prefix mean Occupied Resource ##################################\n"
		);
		our @BANK = ();
		our @BLOCK0;
		our @BLOCK1;
		our @BLOCK2;
		our @BLOCK3;
		our @BLOCK4;
		our @BLOCK5;
		our @BLOCK6;
		our @BLOCK7;
		our @BLOCK8;
		our @BLOCK9;
		our @BLOCK10;
		our @BLOCK11;
		our @BLOCK12;
		our @BLOCK13;
		our @BLOCK14;

#VLX25 divided into 2 banks. Bank0(left portion of center column) and Bank1(right portion of center column)
		our $BANK0_X_RANGE_MIN = 0;
		our $BANK0_X_RANGE_MAX =
		  30;    #27? Its 30 because we include 2 BRAM & 1 DSP rows
		our $BANK0_min_offset  = 0;
		our $BANK0_max_offset  = 3;
		our $BANK1_X_RANGE_MIN = 31;    #28+3
		our $BANK1_X_RANGE_MAX = 62;
		our $BANK1_min_offset  = 3;
		our $BANK1_max_offset  = 7;
		our $device_max_X_range = 62;    #55? #27? Its 62 because we include 2 BRAM & 1 DSP rows
		our $device_max_Y_range = 191;

		#Resource divisors
		our $slice_div  = 1;
		our $BRAM_div   = 8;    #how many BRAMs per column of BRAMs
		our $DSP16_div  = 4;    #how many DSPs per column of BRAMs
		our $FIFO16_div = 8;    #how many FIFO16s per column of BRAMs

		#Max Bank Y range's
		our $BANK_Y_RANGE_MIN = 0;
		our $BANK_Y_RANGE_MAX = 191;

#minimum resource granularity = 191
#Resources divided into blocks of resources for accurate resources allocation and checking
############################################## Left_Paritition AKA BANK0##########################################
		#Block Slice
		our $Bank0_Block0_offset      = 0;
		our $Bank0_BLOCK0_X_RANGE_MIN = 0;
		our $Bank0_BLOCK0_X_RANGE_MAX = 7;

		#Block BRAM
		our $Bank0_BLock1_offset      = 8;
		our $Bank0_BLOCK1_X_RANGE_MIN = 8;
		our $Bank0_BLOCK1_X_RANGE_MAX = 8;

		#Block FIFO16
		our $Bank0_BLock2_offset      = 9;
		our $Bank0_BLOCK2_X_RANGE_MIN = 9;
		our $Bank0_BLOCK2_X_RANGE_MAX = 9;

		#Block Slice
		our $Bank0_Block3_offset      = 2;
		our $Bank0_BLOCK3_X_RANGE_MIN = 10;
		our $Bank0_BLOCK3_X_RANGE_MAX = 17;

		#Block DSP16
		our $Bank0_Block4_offset      = 18;
		our $Bank0_BLOCK4_X_RANGE_MIN = 18;
		our $Bank0_BLOCK4_X_RANGE_MAX = 18;

		#Block Slice
		our $Bank0_Block5_offset      = 3;
		our $Bank0_BLOCK5_X_RANGE_MIN = 19;
		our $Bank0_BLOCK5_X_RANGE_MAX = 30;
##############################################Right_Paritition AKA BANK1############################################
		#Block slice
		our $Bank1_Block0_offset = 3;

		#should use Bank1_block0 offset as a threshold for crossing banks
		our $Bank1_BLOCK0_X_RANGE_MIN = 31;
		our $Bank1_BLOCK0_X_RANGE_MAX = 42;

		#Block BRAM
		our $Bank1_BLock1_offset      = 42;
		our $Bank1_BLOCK1_X_RANGE_MIN = 43;
		our $Bank1_BLOCK1_X_RANGE_MAX = 43;

		#Block FIFO16
		our $Bank1_BLock2_offset      = 43;
		our $Bank1_BLOCK2_X_RANGE_MIN = 44;
		our $Bank1_BLOCK2_X_RANGE_MAX = 44;

		#Block Slice
		our $Bank1_Block3_offset      = 5;
		our $Bank1_BLOCK3_X_RANGE_MIN = 45;
		our $Bank1_BLOCK3_X_RANGE_MAX = 52;

		#Block BRAM
		our $Bank1_Block4_offset      = 51;
		our $Bank1_BLOCK4_X_RANGE_MIN = 53;
		our $Bank1_BLOCK4_X_RANGE_MAX = 53;

		#Block FIFO16
		our $Bank1_Block5_offset      = 51;
		our $Bank1_BLOCK5_X_RANGE_MIN = 54;
		our $Bank1_BLOCK5_X_RANGE_MAX = 54;

		#Block Slice
		our $Bank1_Block6_offset      = 7;
		our $Bank1_BLOCK6_X_RANGE_MIN = 55;
		our $Bank1_BLOCK6_X_RANGE_MAX = 62;
##############################################DCM#############################################
		our $DCM_BLOCK_X_RANGE_MIN = 0;
		our $DCM_BLOCK_X_RANGE_MAX = 0;
		our $DCM_BLOCK_Y_RANGE_MIN = 0;
		our $DCM_BLOCK_Y_RANGE_MAX = 7;
##############################################CLKbuffer############################################
		our $BUFG_BLOCK_X_RANGE_MIN = 0;
		our $BUFG_BLOCK_X_RANGE_MAX = 0;
		our $BUFG_BLOCK_Y_RANGE_MIN = 0;
		our $BUFG_BLOCK_Y_RANGE_MAX = 31;
		our @BLOCK_TYPE = (
							"SLICE",  "RAMB16", "FIFO16",  "SLICE",
							"DSP48",  "SLICE",  "DCM_ADV", "BUFGCTRL",
							"SLICE",  "RAMB16", "FIFO16",  "SLICE",
							"RAMB16", "FIFO16", "SLICE"
		);
		######################internal subroutines##############################
		Allocate();

		#write_dcf();
		#####################internal subroutines##############################
		#############beginning resource allocation using generated dll file######################
		sub Allocate {
###############ALLOCATE##### Prefix 1 means vacant space 0 means occupied space ##################################
			my $trow     = $BANK_Y_RANGE_MIN;    #0
			my $tnumRows = $BANK_Y_RANGE_MAX;    #191
			my $col;
			my $row;
			my @rowMatrix;
#########################BLOCK0#####################################################
			#CHANGE BLOCKS TO SUBROUTINES LATER
			my $tcol     = $Bank0_BLOCK0_X_RANGE_MIN;
			my $tnumCols = $Bank0_BLOCK0_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1S" );
			}
##########################BLOCK1#####################################################
			$tcol     = $Bank0_BLOCK1_X_RANGE_MIN;
			$tnumCols = $Bank0_BLOCK1_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1R" );
			}
##########################BLOCK2#####################################################
			$tcol     = $Bank0_BLOCK2_X_RANGE_MIN;
			$tnumCols = $Bank0_BLOCK2_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1F" );
			}
##########################BLOCK3#####################################################
			$tcol     = $Bank0_BLOCK3_X_RANGE_MIN;
			$tnumCols = $Bank0_BLOCK3_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1S" );
			}
##########################BLOCK4#####################################################
			$tcol     = $Bank0_BLOCK4_X_RANGE_MIN;
			$tnumCols = $Bank0_BLOCK4_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1D" );
			}
##########################BLOCK5###################################################
			$tcol     = $Bank0_BLOCK5_X_RANGE_MIN;
			$tnumCols = $Bank0_BLOCK5_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1S" );
			}
##########################BLOCK6#####################################################
			$tcol     = $Bank1_BLOCK0_X_RANGE_MIN;
			$tnumCols = $Bank1_BLOCK0_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1S" );
			}
##########################BLOCK7#####################################################
			$tcol     = $Bank1_BLOCK1_X_RANGE_MIN;
			$tnumCols = $Bank1_BLOCK1_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1R" );
			}
##########################BLOCK8#####################################################
			$tcol     = $Bank1_BLOCK2_X_RANGE_MIN;
			$tnumCols = $Bank1_BLOCK2_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1F" );
			}
##########################BLOCK9#####################################################
			$tcol     = $Bank1_BLOCK3_X_RANGE_MIN;
			$tnumCols = $Bank1_BLOCK3_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1S" );
			}
##########################BLOCK10#####################################################
			$tcol     = $Bank1_BLOCK4_X_RANGE_MIN;
			$tnumCols = $Bank1_BLOCK4_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1R" );
			}
##########################BLOCK11#####################################################
			$tcol     = $Bank1_BLOCK5_X_RANGE_MIN;
			$tnumCols = $Bank1_BLOCK5_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1F" );
			}
##########################BLOCK12#####################################################
			$tcol     = $Bank1_BLOCK6_X_RANGE_MIN;
			$tnumCols = $Bank1_BLOCK6_X_RANGE_MAX;
			for ( $col = $tcol ; $col <= $tnumCols ; $col++ ) {
				push( @rowMatrix, "1S" );
			}
##########################BLOCK13#####################################################
##########################BLOCK14#####################################################
#############################FINAL Allocation#######################################
			for ( $row = $trow ; $row <= $tnumRows ; $row++ ) {
				push( @BANK, [@rowMatrix] );
			}

			#print dilf file output
			for ( $row = 0 ; $row <= $tnumRows ; $row++ ) {
				for ( $col = 0 ; $col <= $tnumCols ; $col++ ) {
					print OUT ("$BANK[$row][$col] ");
				}
				print OUT "\n";
			}
		}
###############ALLOCATE_END#####1 means vacant space 0 means occupied space##################################
############DCM AND BUFG ALLOCATION##############################################
		create_dcf();

		sub create_dcf {
####################create dcf file#############################################################################
			reset_dir();
			open( OUTFILE_dcf, ">PR_Automated/design$iteration/top.dcf" )
			  or die
			  "Cannot open output file PR_Automated/design$iteration/top.dcf!";
			print OUTFILE_dcf (
				"\n
###############################################################################################################
# Generated by preliminary DAPR tool implementation		$time_stamp_date
###############################################################################################################

#DAPR tool generated physical constraints\n\n"
			);
################################################################################################################
#######################Write SA PRR placement Algorithm here ###########
			SA_PRR();

			sub SA_PRR {
######generate initial polish expression############
				#our @E0;    #inital solution
				#our @module_list_test = qw(count count1 count2 count3 static);
				print report_file "module list test= @module_list_fp, max_slice_reqs = @max_slice_reqs\n";
				
				#our @module_list_fp = qw(FFT FFT256 FFT128 StaticA);
								
				our @module_list_test = @module_list_fp;
				
				#our @max_slice_reqs   = qw(1840 1136 789 33);
				our @max_slice_reqs_test   = @max_slice_reqs;
				
				
				
				our $device_max_x_range_fp = 55;
				our $device_max_y_range_fp = 191;
				our $init_fp_error         = 0;
				
				print "@module_list_test\n";
				$N = @module_list_test;
				print "N = $N\n"; 
################intial solution of all PRRs placed vertically################
				my $lp = 0;
				
				

				if ( $iteration == 1 ) {
					foreach my $module (@module_list_test) {
						####check if PRRs placed vertically crosses design chip area and set $init_fp_error flag #########
						$total_V_slice_reqs = $total_V_slice_reqs +
						  ceil( sqrt( $max_slice_reqs_test[$lp] ) );
						$total_H_slice_reqs = $total_H_slice_reqs +
						  ceil( sqrt( $max_slice_reqs_test[$lp] ) );
						
						if ( $total_V_slice_reqs >= $device_max_x_range_fp ) {
							$init_fp_error = 1;
						}
						if ( $total_H_slice_reqs >= $device_max_y_range_fp ) {
							$init_fp_error = 1;
						}
						####check if PRRs placed vertically crosses design chip area#########
						$lp++;
						push( @E0, $lp );
						if ( $lp == 1 ) {

							#$lp++;
							next;
						}
						else {
							push( @E0, "V" );
						}
					}
				}
				
				@E_orig = @E0;
				print "@E0\n";
				print "Slice req = @max_slice_reqs_test\n";
				print "Total V slices $total_V_slice_reqs\n";
				print "Total H slices $total_H_slice_reqs\n";
				print "FP_packing error = $init_fp_error\n";
################ end intial solution of all PRRs placed vertically################
##################floorplan intial solution and calculate clock frequency#####################
		########################Main floorplanner loop#######################################		
				if ($iteration < $rand_iter){
					print "Random PRR placement, iteration = $iteration and rand_iter = $rand_iter\n";
					rand_PRR_placement();

		
		#########################PAR ERROR CHECK#############################
					if ( $PAR_error_flag == 0 ) {
						$iteration++;	
					} else {
						
						print "******************PAR error\n***************************";
					
						
						if ($PAR_error_count > 2){
							my $int_frag_x++;    #floorplanner threshold value for increasing slice range
							my $int_frag_y++;    #floorplanner threshold value for increasing slice range							
							$PAR_error_count = 0;
			
							$PAR_error_count_ws++;
							
							if ($PAR_error_count_ws > 1){
						    	$white_space++;    #0% whitespace allocated
						    	$PAR_error_count_ws = 0;							
							}
						
						$PAR_error_flag = 0;    #reset PAR_Error_flag
						return;
						                
						}
					}	
					
			#########################END PAR ERROR CHECK#############################		
									
				}else{
						
					print "Simulated annealing PRR placement, iteration = $iteration and rand_iter = $rand_iter\n";
				
					SA_PRR_algorithm();
				
				#########################PAR ERROR CHECK#############################
					if ( $PAR_error_flag == 0 ) {
						$iteration++;	
					} else {
						
						print "******************PAR error\n***************************";
					
						if ($PAR_error_count > 2){
							my $int_frag_x++;    #floorplanner threshold value for increasing slice range
							my $int_frag_y++;    #floorplanner threshold value for increasing slice range							
							$PAR_error_count = 0;
			
							$PAR_error_count_ws++;
							
							if ($PAR_error_count_ws > 1){
						    	$white_space++;    #0% whitespace allocated
						    	$PAR_error_count_ws = 0;							
							}
							
						$PAR_error_flag = 0;    #reset PAR_Error_flag
						return;
						                
						}
					}	
					
			#########################END PAR ERROR CHECK#############################		
				
				
					
					
				}
				
	###################################################################################			
				
				
				
				sub rand_PRR_placement {
					our @E_stack;
					##begin initialization###########
					if ( $iteration == 1 ) {
						
						#@E0 = qw (1 V 2 V 3 V 4 V 5 V);
						create_fp_stack();
						; # update variable @E_stack_fp with perturbed new stack
############generate final floorplan array and stack#############################
	  #create_fp_stack(); # update variable @E_stack_fp with perturbed new stack
						############generate final floorplan array and stack#############################
						my $module_name;
						my $module_slice_reqs;

			
					}
					########begin subroutine create fp stack
					sub create_fp_stack {
						my $lp = 0;
						my $a;
						my $b;
						my $c;
						@E_stack = ();
						foreach my $value (@E0) {

							#print "value = $value\n";
							if ( $value ne 'V' and $value ne 'H' )
							{    #check if $value is an operand
								    #print "entering operand\n";
								push( @E_stack, $value );
							}
							if ( $value eq 'V' or $value eq 'H' )
							{       #check if $value is an operator
								    #print "entering operator\n";
								
								
								$a = pop(@E_stack);
								
								
								$b = pop(@E_stack);
								
								$c = $a . $value . $b;

								#push (@E_stack_fp, $b);
								#push (@E_stack_fp, $value);
								#push (@E_stack_fp, $a);
								push( @E_stack, $c );
							}
							$lp++;
						}
						my $size = @E_stack;

						print "size $size\n";
						print "@E_stack\n";
						my $E_stack_fp = reverse(@E_stack);

						#print "$E_stack_fp\n";
						@E_stack_fp = split( //, $E_stack_fp );

						#print "@E_stack_fp\n";
					}    #end_subroutine create fp stack
					##end if, end begin initialization###########
					############generate initial randomized floorplan from array stack #############################
					
					
				
					
					
				sub PRR_placement {

					my $lp = 0;
					print report_file "\n Intital stack = @E_stack_fp for iteration $iteration\n";
					
					@place_contraints_module =();	
					@placement_contraints_X_min = ();
					@placement_contraints_X_max = ();
					@placement_contraints_Y_min = ();
					@placement_contraints_Y_max = ();
					
					foreach my $value (@E_stack_fp) {

						
						if ( $value ne 'V' and $value ne 'H' ) {    #check if $value is an operand
							$module_name = $module_list_test[ $value - 1 ];
							$module_slice_reqs = $max_slice_reqs_test[ $value - 1 ];
							print report_file "$module_name\n";
							print report_file "$module_slice_reqs\n";
							######intial module placement stars from left corner of the device#########
							
							
#							if ( $value eq '1' ) {
							if ( $lp == 0 ) {
								print report_file "entering operand $value\n";
								$x_min = $x_min_global; #intial value = 0 
								$y_min = $y_min_global; #intial value = 0

#would aspect ratio equal to the device make it easier to pack???? then
#my $t=$device_max_x_range_fp+$device_max_y_range_fp;
#$y_top_right = ceil ((($module_slice_reqs/$t)*$device_max_y_range_fp) + $int_frag_y);
								$y_max = $y_min + ceil(sqrt($module_slice_reqs) + $int_frag_y );
									 											   
								$x_max = $x_min + ceil(sqrt($module_slice_reqs) + $int_frag_x );
									
								####check if y_max ends at CLB boundary####
							   	if ($y_max % 2 == 1)
								{
									    # odd ends at CLB boundary
								}
								else
								{
									    # even
									    $y_max = $y_max+1; #make it odd
								}
								#############end check CLB coundary	 
								
								####check if y_min starts at CLB boundary####
							   	if ($y_min % 2 == 0)
								{
									    # even, so starts at CLB boundary
								}
								else
								{
									    # odd
									    $y_min = $y_min+1; #make it even
								}
								#############end check CLB coundary
								
								###check if x_max ends at CLB boundary####
							   	if ($x_max % 2 == 1)
								{
									    # odd ends at CLB boundary
								}
								else
								{
									    # even
									    $x_max = $x_max+1; #make it odd
								}
								#############end check CLB coundary	 ######  
								
								####check if x_min starts at CLB boundary####
							   	if ($x_min % 2 == 0)
								{
									    # even, so starts at CLB boundary
								}
								else
								{
									    # odd
									    $x_min = $x_min+1; #make it even
								}
								#############end check CLB coundary
									   
								#############Check if floorplan crosses device range###################
								
								print report_file "x_min:$x_min y_min:$y_min x_max:$x_max y_max:$y_max\n" ;	
								 if(($x_min > $device_max_x_range_fp) or ($x_max > $device_max_x_range_fp) or ($y_min > $device_max_y_range_fp) or ($y_max > $device_max_y_range_fp )){
								 	
								 	print report_file "***************invalid initial placement floorplan***********\n";
									return 0; 	
								 	
								 	
								 }	
									print report_file "***************valid initial placement floorplan***********\n";
							
								
								#############End Check if floorplan crosses device range###################	   
									   
									   
									   
									   
								push( @place_contraints_module,$module_name );
								push( @placement_contraints_X_min, $x_min );
								push( @placement_contraints_X_max, $x_max );
								push( @placement_contraints_Y_min, $y_min );
								push( @placement_contraints_Y_max, $y_max );
								print(" x_min:$x_min y_min:$y_min x_max:$x_max y_max:$y_max\n" );
								
								$x_min_last = $x_min;
								$y_min_last = $y_min;
								$x_max_last = $x_max;
								$y_max_last = $y_max;
								$x_max_global =  max( $x_max_last, $x_max_global );
								print "x_max_global = $x_max_global\n";
								$lp++;
								next;
							}
							else {
								############placement for horizontal cut##################
								print "entering operator $value lp = $lp \n";
								my $cut_type = $E_stack_fp[ $lp - 1 ];
								print "cut_type = $cut_type\n";
								if ( $cut_type eq 'H' ) {
									
									print "***************Entering H cut\n";
									$x_min = $x_min_last;
									$y_min = $y_max_last + $white_space;
									$y_max =
									  $y_min +
									  ceil(
											sqrt($module_slice_reqs) +
											  $int_frag_y );
									$x_max =
									  $x_min +
									  ceil(
											sqrt($module_slice_reqs) +
											  $int_frag_x );
											  	
								####check if y_max ends at CLB boundary####
							   	if ($y_max % 2 == 1)
								{
									    # odd ends at CLB boundary
								}
								else
								{
									    # even
									    $y_max = $y_max+1; #make it odd
								}
								#############end check CLB coundary	 
								
								####check if y_min starts at CLB boundary####
							   	if ($y_min % 2 == 0)
								{
									    # even, so starts at CLB boundary
								}
								else
								{
									    # odd
									    $y_min = $y_min+1; #make it even
								}
								#############end check CLB coundary
								
								###check if x_max ends at CLB boundary####
							   	if ($x_max % 2 == 1)
								{
									    # odd ends at CLB boundary
								}
								else
								{
									    # even
									    $x_max = $x_max+1; #make it odd
								}
								#############end check CLB coundary	 ######  
								
								####check if x_min starts at CLB boundary####
							   	if ($x_min % 2 == 0)
								{
									    # even, so starts at CLB boundary
								}
								else
								{
									    # odd
									    $x_min = $x_min+1; #make it even
								}
								#############end check CLB coundary
								#############Check if floorplan crosses device range###################
								
								print report_file "x_min:$x_min y_min:$y_min x_max:$x_max y_max:$y_max\n" ;	
								 if(($x_min > $device_max_x_range_fp) or ($x_max > $device_max_x_range_fp) or ($y_min > $device_max_y_range_fp) or ($y_max > $device_max_y_range_fp )){
								 	
								 	print report_file "***************invalid H cut floorplan***********\n";
									return 0; 	
								 	
								 	
								 }	
									
								print report_file "***************valid H cut floorplan***********\n";
								
								#############End Check if floorplan crosses device range###################	   
									   	   
									
									   
									push( @place_contraints_module, $module_name );
									push( @placement_contraints_X_min, $x_min );
									push( @placement_contraints_X_max, $x_max );
									push( @placement_contraints_Y_min, $y_min );
									push( @placement_contraints_Y_max, $y_max );
									print( " x_min:$x_min y_min:$y_min x_max:$x_max y_max:$y_max\n" );
									$x_min_last = $x_min;
									$y_min_last = $y_min;
									$x_max_last = $x_max;
									$y_max_last = $y_max;
									$x_max_global =
									  max( $x_max_last, $x_max_global );
									print "x_max_global = $x_max_global\n";
								}
								elsif ( $cut_type eq 'V' ) {
									############placement for veritcal cut####################
									print "*************Entering V cut\n";
									$x_min = $x_max_global + $white_space;
									$y_min = $y_min_global;
									$y_max =
									  $y_min +
									  ceil(
											sqrt($module_slice_reqs) +
											  $int_frag_y );
									$x_max =
									  $x_min +
									  ceil(
											sqrt($module_slice_reqs) +
											  $int_frag_x );
								
								
								
								
								####check if y_max ends at CLB boundary####
							   	if ($y_max % 2 == 1)
								{
									    # odd ends at CLB boundary
								}
								else
								{
									    # even
									    $y_max = $y_max+1; #make it odd
								}
								#############end check CLB coundary	 
								
								####check if y_min starts at CLB boundary####
							   	if ($y_min % 2 == 0)
								{
									    # even, so starts at CLB boundary
								}
								else
								{
									    # odd
									    $y_min = $y_min+1; #make it even
								}
								#############end check CLB coundary
								
								###check if x_max ends at CLB boundary####
							   	if ($x_max % 2 == 1)
								{
									    # odd ends at CLB boundary
								}
								else
								{
									    # even
									    $x_max = $x_max+1; #make it odd
								}
								#############end check CLB coundary	 ######  
								
								####check if x_min starts at CLB boundary####
							   	if ($x_min % 2 == 0)
								{
									    # even, so starts at CLB boundary
								}
								else
								{
									    # odd
									    $x_min = $x_min+1; #make it even
								}
								#############end check CLB coundary
								#############Check if floorplan crosses device range###################
								
								print report_file "x_min:$x_min y_min:$y_min x_max:$x_max y_max:$y_max\n" ;	
								 if(($x_min > $device_max_x_range_fp) or ($x_max > $device_max_x_range_fp) or ($y_min > $device_max_y_range_fp) or ($y_max > $device_max_y_range_fp )){
								 	
								 	print report_file "***************invalid V cut floorplan***********\n";
									return 0; 	
								 	
								 	
								 }	
									print report_file "***************valid V cut floorplan***********\n";
								#############End Check if floorplan crosses device range###################	   
									   	   
											  
											  
									push( @place_contraints_module, $module_name );
									push( @placement_contraints_X_min, $x_min );
									push( @placement_contraints_X_max, $x_max );
									push( @placement_contraints_Y_min, $y_min );
									push( @placement_contraints_Y_max, $y_max );
									print(" x_min:$x_min y_min:$y_min x_max:$x_max y_max:$y_max\n" );
									$x_min_last = $x_min;
									$y_min_last = $y_min;
									$x_max_last = $x_max;
									$y_max_last = $y_max;
									$x_max_global = max( $x_max_last, $x_max_global );
									#print "x_max_global = $x_max_global\n";
								}
							}
							######intial module placement stars from left corner of the device#########
						}
						$lp++;
					}
				
					print report_file "**********Placement successful for iteration $iteration******************\n";
					return 1;
					
				}
				
				############################################end subroutine PRR_placement##########################
				
				
				
					###################Begin Random perturbation#####################
					###################three types of random perturbation performed#####################
				
					my $M=3;
					my $temp_size = @E0;
			
					print "ts =  $temp_size \n";
					if ($temp_size <= 3){
					
					 $M = 2;
					 print("####################Swap Move cancelled###################\n");	
					
					}
					
					##############change starting location every 2*N iterations###################
					
					my $permutation = 2*$N;
			
					
					if ($iteration % 2 == 0){
						$Move = 0; 
						print report_file "Starting location changed, permutation = $permutation\n";
					##############change starting location every 5 iterations###################
					}else{
						$Move = int( rand($M) ) + 1;	
					}
					
			#		$Move = 4; ###temporarily set to check swap_m3
					
					
					print report_file "Entering Random pertubation \n";
					############create placements#####################
					
					my $ret_value;
					if ($iteration == 1){
						print report_file "Create initial placement for iteration = $iteration\n";
						$ret_value = PRR_placement(); 
						
						while ($ret_value == 0){
							
								
							perturbation($Move);
							$ret_value = PRR_placement();
							$Move = int( rand($M) ) + 1;
							#$Move = 4;
							print report_file "Move value = $Move\n";
							print report_file "PRR placement return value = $ret_value\n";
							
						}
					}else{
						print report_file "Random placement for iteration = $iteration\n";
						perturbation($Move);
						$ret_value = PRR_placement();
						while ($ret_value == 0){
							my $pert_ret_value = perturbation($Move);
							if($pert_ret_value == 0){
								$Move = int( rand(2) ) + 1;
							}
							else{
								$Move = int( rand($M) ) + 1;	
							}
							$ret_value = PRR_placement();
							
							#$Move = 4;
							print report_file "Move value = $Move\n";
							print report_file "PRR placement return value = $ret_value\n";
						}
					}
						
				   ############end create  placements#####################	
						
					print report_file "Exiting Random pertubation \n";
					
					#PRR_placement();


					sub perturbation {
						my $Move = $_[0];
##############change starting location every 5 iterations###################

###########################################################################
						print "############### M value = $Move ###############\n";
						
						switch ($Move) {
							#######################SWAP adjacent operands##########################
							case 1 {

								#print "swap operands \n";
								#print "old stack = @E0\n";
								#print "swapped stack = @new_E0\n";
								print "old_stack_fp = @E_stack_fp\n";
								swap_M1();
								return 1;
								sub swap_M1 {
									our @new_E0;
									@new_E0 = @E0;
									our $size = @new_E0;
									print "stack size = $size\n";
									our $rand_int = int( rand($size) );
									print "random size integer = $rand_int\n";
									print "stack_value = $new_E0[$rand_int]\n";
									our $temp_op1;
									our $temp_op1_index;
									our $temp_op2;
									our $temp_op2_index;
									find_adjacent_operands();

									sub find_adjacent_operands {
										if (     ( $new_E0[$rand_int] ne 'V' )
											 and ( $new_E0[$rand_int] ne 'H' ) )
										{
											$temp_op1 = $new_E0[$rand_int];
											$temp_op1_index = $rand_int;
											if ( ( $rand_int + 1 ) < $size ) {
												my $i = $rand_int + 1;
												forward_traversal_M1($i);
											}
											else {
												my $i = $rand_int - 1;
												reverse_traversal_M1($i);
											}
										}
										else {
											$rand_int = int( rand($size) );
											find_adjacent_operands();
										}
									}
									$new_E0[$temp_op1_index] = $temp_op2;
									$new_E0[$temp_op2_index] = $temp_op1;
									print "old stack = @E0\n";
									print "swapped stack = @new_E0\n";
									print "old_stack_fp = @E_stack_fp\n";
									@E0 = @new_E0;
									create_fp_stack();
									print "new_stack_fp = @E_stack_fp\n";

									#end subroutine find_adjacent_operands
									######################Subroutines for traversing stack##############
									sub forward_traversal_M1 {
										my $i = $_[0];
										$temp_op2       = $new_E0[$i];
										$temp_op2_index = $i;
										if (    ( $temp_op2 eq 'V' )
											 or ( $temp_op2 eq 'H' ) )
										{
											my $ii = $i + 1;
											if ( $ii < $size ) {
												forward_traversal_M1($ii);
											}
											else {
												my $iii = $rand_int - 1;
												reverse_traversal_M1($iii);
											}
										}
									}

									sub reverse_traversal_M1 {
										my $i = $_[0];
										$temp_op2       = $new_E0[$i];
										$temp_op2_index = $i;
										if (    ( $temp_op2 eq 'V' )
											 or ( $temp_op2 eq 'H' ) )
										{
											my $ii = $i - 1;
											if ( $ii >= 0 ) {
												reverse_traversal_M1($ii);
											}
											else {
												my $iii = $rand_int + 1;
												forward_traversal_M1($iii);
											}
										}
									}
									#####################Subroutines for traversing stack##############
									
								}    #end subroutine swap
							}
							#######################SWAP operands##########################
							#######################complement an operator##########################
							case 2 {
								print
								  "complement a non-zero chain of operators \n";
								complement_M2();

								return 1;
								sub complement_M2 {
									our @new_E0;
									@new_E0 = @E0;
									our $size = @new_E0;
									print "stack size = $size\n";
									our $operator_flag                   = 0;
									our @operator_chain                  = ();
									our @operator_chain_starting_indexes = ();
									our @operator_chain_index            = ();
									our @operator_chain_ending_indexes = ();
									our $consecutive_operators           = 0;
									
									our $flag_operand                    = 0;
									our @operand_chain                   = ();
									our @operand_chain_index  = ();
									our $consecutive_operands = 0;
									
									
									find_chain();
									
									print "operator_chain = @operator_chain\n";
									print "operator_chain_index = @operator_chain_index\n";
									print "operator_chain_starting_indexes = @operator_chain_starting_indexes\n";
									print "operator_chain_ending_indexes = @operator_chain_ending_indexes\n";
									
									print "operand_chain = @operand_chain\n";
									print "operand_chain_indexes = @operand_chain_index\n";
									
									

									sub find_chain {
										for ( my $i = 0 ; $i < $size ; $i++ ) {
											if (    ( $new_E0[$i] eq 'V' )
												 or ( $new_E0[$i] eq 'H' ) )
											{
												push( @operator_chain,
													  $new_E0[$i] );
												push( @operator_chain_index,
													  $i );
												$operator_flag = 1;
												if ( $consecutive_operators == 0 )
												{
													push(
														@operator_chain_starting_indexes,
														$i );
												}
												if ( ( $i + 1 ) < $size ) {
													if (
														 (
														   $new_E0[ $i + 1 ] eq
														   'V'
														 )
														 or ( $new_E0[ $i + 1 ]
															  eq 'H' )
													  )
													{
														$consecutive_operators
														  = 1;
													}
													else {
														$consecutive_operators
														  = 0;
														 push (@operator_chain_ending_indexes, $i);
													}
												}
												else {
													
													
													last;
												}
											}
											else {
												$operator_flag         = 0;
												$consecutive_operators = 0;
												push( @operand_chain,
													  $new_E0[$i] );
												push( @operand_chain_index,
													  $i );
											}

				 #if ($operator_flag == '1'  and $consecutive_operators == '1'){
				 #		push (@operator_chain_starting_indexes, $i);
				 #}
										}
										
#										
#										if ( !@operator_chain_ending_indexes )
#												{
#													push(@operator_chain_ending_indexes, 0 );
#													print ("#########paddding indexes#############\n");
#												}
										
										
									} 
									
									#################END subroutine find_chain###############
									our $rand_int = int rand($size);
									while (
										($rand_int) < $operator_chain_index[0] )
									{
										$rand_int = int( rand($size) );
									}
									print "random size integer = $rand_int\n";
									print "stack_value = $new_E0[$rand_int]\n";
									complement_operator_chain();
									print "old stack = @E0\n";
									print "swapped stack = @new_E0\n";
									print "old_stack_fp = @E_stack_fp\n";
									@E0 = @new_E0;
									create_fp_stack();
									print "new_stack_fp = @E_stack_fp\n";

									sub complement_operator_chain {
										my $size_operator_chain_starting_indexes
										  = @operator_chain_starting_indexes;
										my $rand_chain_select =
										  int(
											rand(
												$size_operator_chain_starting_indexes
											)
										  );
										my $chain_start =
										  $operator_chain_starting_indexes
										  [$rand_chain_select];

		#my $chain_end = $operator_chain_starting_indexes[$rand_chain_select+1];
										my $chain_end;
										if ( $rand_chain_select + 1 <
											$size_operator_chain_starting_indexes
										  )
										{
											$chain_end =
											  $operator_chain_starting_indexes
											  [ $rand_chain_select + 1 ];
										}
										else {
											$chain_end = $size;
										}
										print "Chain_start = $chain_start\n";
										print "Chain_end = $chain_end\n";
										for ( my $i = $chain_start ;
											  $i < $chain_end ;
											  $i++ )
										{
											if ( $new_E0[$i] eq 'V' ) {
												$new_E0[$i] = 'H';
												next;
											}
											if ( $new_E0[$i] eq 'H' ) {
												$new_E0[$i] = 'V';
												next;
											}
										}
									}  #end subroutine complement_operator_chain
									#####################Subroutines for travering stack##############
								
									
								}    #end subroutine complement_M2
							}
							#######################complement an operator##########################
							#######################SWAP adjacent operand and operator##########################
							case 3 {

								#print "old_stack_fp = @E_stack_fp\n";
								my $temp_size = @E0;
								
								if ($temp_size > 3 ) {
									
									my $temp_ret_value = swap_M3();
									if ($temp_ret_value == 0) {
										print report_file "Swap failed\n";
										return 0;
									}else
									{
										print report_file "Swap succesful\n";
										return 1;
									}
								}
								else {
									
									print ("Array size too small for swapping\n");
									
								} 
								
								
						
								
								sub swap_M3 {
									our @new_E0;
									@new_E0 = @E0;
									our $size = @new_E0;
									
									print report_file "Entering SWAP M3, Stack = @new_E0\n";
									print report_file "stack size = $size\n";
									our $rand_int = int( rand($size) );
									print report_file "random size integer = $rand_int\n";
									print report_file "stack_value = $new_E0[$rand_int]\n";
									our $temp_op1;
									our $temp_op1_index;
									our $temp_op2;
									our $temp_op2_index;
									our $operator_flag                   = 0;
									our @operator_chain                  = ();
									our @operator_chain_starting_indexes = ();
									our @operator_chain_index            = ();
									our @operator_chain_ending_indexes = ();
									our $consecutive_operators           = 0;
									
									our $flag_operand                    = 0;
									our @operand_chain                   = ();
									our @operand_chain_index  = ();
									our $consecutive_operands = 0;
									our $rand_chain_select;
									
									find_chain();
									
									print report_file "operator_chain = @operator_chain\n";
									print report_file "operator_chain_index = @operator_chain_index\n";
									print report_file "operator_chain_starting_indexes = @operator_chain_starting_indexes\n";
									print report_file "operator_chain_ending_indexes = @operator_chain_ending_indexes\n";
									
									print report_file "operand_chain = @operand_chain\n";
									print report_file "operand_chain_indexes = @operand_chain_index\n";
									
				
									our $done = 0;    #done = false
									my $chain_iter = 0;
									my $chain_size = @operator_chain;
									while ( not($done) ) {
										find_adjacent_operand_operator();
										$chain_iter ++;
										if($chain_iter > ($size*2)){
											$done = 0;
											print "no feasible Swap_M3 move possible for current floorplan\n";
											$chain_iter = 0;
											return 0;
										}
										
									}							
									#$done = 0;
									
									
##									$new_E0[$temp_op1_index] = $temp_op2;
##									$new_E0[$temp_op2_index] = $temp_op1;
									print report_file "old stack = @E0\n";
									print report_file "swapped stack = @new_E0\n";
									print report_file "old_stack_fp = @E_stack_fp\n";
									@E0 = @new_E0;
									create_fp_stack();
									print report_file "new_stack_fp = @E_stack_fp\n";

									sub find_adjacent_operand_operator {
										
										my $rand_swap = 0;
										
										
										if (!@operator_chain_ending_indexes){
											
											print report_file "Forward swap not possible for current floorplan\n";
										
											$rand_swap = 0;											
											
										}else{
										
											$rand_swap = int(rand(2));
										
										
										}
										print report_file ("rand_swap = $rand_swap\n");
										
										if ($rand_swap == '0'){
											
											print report_file ("swap backward\n");
											
											
											swap_backward();	
											
										}else {
											
											print report_file ("swap forward\n");
											swap_forward();
											
										}
										
										
										sub swap_forward{
											
											
										my $size_operator_chain_index = @operator_chain_ending_indexes;
										$rand_chain_select = int(rand($size_operator_chain_index) );
										
										print "rand_chain_select_initial = $rand_chain_select\n";	
										
										$temp_op1_index =
										  $operator_chain_ending_indexes
										  [$rand_chain_select];
										  
										$temp_op1 =
										  $new_E0
										  [ $temp_op1_index ];
										  
										  $temp_op2_index =
										  ( ($operator_chain_ending_indexes [$rand_chain_select]) + 1 );
										  
										$temp_op2 =
										  $new_E0
										  [$temp_op2_index];
										
										print "temp_op1_index = $temp_op1_index\n";
										print "temp_op1 = $temp_op1\n";
										print "temp_op2_index = $temp_op2_index\n";
										print "temp_op2 = $temp_op2\n";
										
										my $i_op = $temp_op1_index;
										my $iplus2_op = $temp_op2_index + 1; 
										my $iplus1_op = $temp_op2_index;
										
										print "i $i_op\n";
										print "iplus2 $iplus2_op\n"; 
					
										my $number_of_operands_i;
										my $number_of_operators_Niplus1;
															
										$number_of_operands_i        = 0;
										$number_of_operators_Niplus1 = 0;
								
								
										for ( my $i = $iplus1_op ;
											  $i >= 0 ;
											  $i-- )
										{
											if (    ( $new_E0[$i] eq 'V' )
												 or ( $new_E0[$i] eq 'H' ) )
											{
												
												$number_of_operators_Niplus1++;
												
											}
										}
										
										for ( my $i = $i_op ;
											  $i >= 0 ;
											  $i-- )
										{
											if (    ( $new_E0[$i] ne 'V' )
												 and ( $new_E0[$i] ne 'H' ) )
											{
												$number_of_operands_i++;
												
												
											}
										}
		
										print "number of operands = $number_of_operands_i\n";
										print "number of operators_Niplus1 = $number_of_operators_Niplus1\n";
										
										
								
										
											
											print "new_E0[(i_op)]  = $new_E0[($i_op)] \n";
											print "new_E0[(iplus2_op)] = $new_E0[($iplus2_op)]\n"; 
											
										
										if (  ($new_E0[($i_op)])  ne  $new_E0[$iplus2_op]) {	
											
											
											
												
											if ( (2*$number_of_operators_Niplus1) < $iplus1_op){
												
												$done = 1;
												print "done = 1\n";
												print "SWAP accepted ($number_of_operators_Niplus1*2) < $iplus1_op\n";
												$new_E0[$temp_op1_index] = $temp_op2;
												$new_E0[$temp_op2_index] = $temp_op1;
#												print "old stack = @E0\n";
#												print "swapped stack = @new_E0\n";
#												print "old_stack_fp = @E_stack_fp\n";
#												
											}else
											{		print "SWAP rejected ($number_of_operators_Niplus1*2) < $iplus1_op\n";
													print "done = 0\n";
												
													print "old stack = @E0\n";
													print "swapped stack = @new_E0\n";
													print "old_stack_fp = @E_stack_fp\n";
											
											}
											
												$done = 1;
												print "done = 1\n";
												print "SWAP accepted\n";
												
												
											
										}
										else{
									  		print "SWAP rejected ($new_E0[($i_op)])  ne  ($new_E0[($iplus2_op)]) \n";
									  		
									  		$done= 0;
										}
											
										}#end swap forward
										
										sub swap_backward{
											
										my $size_operator_chain_index = @operator_chain_starting_indexes;
										$rand_chain_select = int(rand($size_operator_chain_index) );
										
										print "rand_chain_select_initial = $rand_chain_select\n";	
										#while (($rand_chain_select < 1) or ($operator_chain_starting_indexes [$rand_chain_select] > ($size-2) )){
#										while ($rand_chain_select < 1) {
#											
#											print report_file "size_operator_chain_index = $size_operator_chain_index\n";
#											print report_file "operator_chain_starting_indexes = @operator_chain_starting_indexes\n";	
#											$rand_chain_select = int(rand($size_operator_chain_index) );	
#											print "rand_chain_select_after = $rand_chain_select\n";
#											print "swap_backward\n";
#										}
										
										
										print "rand_chain_select_final = $rand_chain_select\n";
										
										$temp_op1 =
										  $new_E0
										  [ $operator_chain_starting_indexes
										  [$rand_chain_select] ];
										$temp_op1_index =
										  $operator_chain_starting_indexes
										  [$rand_chain_select];
										$temp_op2 =
										  $new_E0
										  [ ($operator_chain_starting_indexes[$rand_chain_select])- 1];
										$temp_op2_index =
										  ( ($operator_chain_starting_indexes [$rand_chain_select]) - 1 );
										
										my $number_of_operands_i;
										my $number_of_operators_Niplus1;
										
										my $i_op = $temp_op2_index;
										my $iplus1_op= $temp_op1_index; 
										
										print "i $i_op\n";
										print "iplus1 $iplus1_op\n"; 
										
										
										#my $stack_index =
										 # $operator_chain_ending_indexes
										 # [$rand_chain_select];
										$number_of_operands_i        = 0;
										$number_of_operators_Niplus1 = 0;
										#print "stack index\n";

										for ( my $i = $iplus1_op ;
											  $i >= 0 ;
											  $i-- )
										{
											if (    ( $new_E0[$i] eq 'V' )
												 or ( $new_E0[$i] eq 'H' ) )
											{
												
												$number_of_operators_Niplus1++;
												
											}
										}
										
										for ( my $i = $i_op ;
											  $i >= 0 ;
											  $i-- )
										{
											if (    ( $new_E0[$i] ne 'V' )
												 and ( $new_E0[$i] ne 'H' ) )
											{
												$number_of_operands_i++;
												
												
											}
										}
											
										print "number of operands = $number_of_operands_i\n";
										print "number of operators_Niplus1 = $number_of_operators_Niplus1\n";
										
										
								
										
											
											print "new_E0[($i_op-1)]  = $new_E0[($i_op-1)] \n";
											print "new_E0[($i_op + 1)] = $new_E0[($i_op + 1)]\n"; 
											
										
										if (  ($new_E0[($i_op-1)])  ne  $new_E0[$iplus1_op]) {	
											
												
											if ( (2*$number_of_operators_Niplus1) < $iplus1_op){
												
												$done = 1;
												print "done = 1\n";
												print "SWAP accepted ($number_of_operators_Niplus1*2) < $iplus1_op\n";
												$new_E0[$temp_op1_index] = $temp_op2;
												$new_E0[$temp_op2_index] = $temp_op1;
#												print "old stack = @E0\n";
#												print "swapped stack = @new_E0\n";
#												print "old_stack_fp = @E_stack_fp\n";
												
											}else
											{		print "SWAP rejected ($number_of_operators_Niplus1*2) < $iplus1_op\n";
													print "done = 0\n";
#													
#													print "old stack = @E0\n";
#													print "swapped stack = @new_E0\n";
#													print "old_stack_fp = @E_stack_fp\n";
											
											}
											
										}
										else{
									  		print "SWAP rejected ($new_E0[($i_op-1)])  ne  ($new_E0[($i_op + 1)]) \n";
									  		
									  		$done= 0;
										}
											
										}
										
										
										
										
									}# end subroutine find adjacent_operrator_operand
									return  1;
								}#end subroutine swap_m3
							}
							#######################SWAP adjacent operand and operator##########################
							######################Change starting location##########################
							else {
								
								print report_file "total_H_slice_reqs = $total_H_slice_reqs\n";
								print report_file "total_V_slice_reqs = $total_V_slice_reqs\n";
								
								$old_xmin_global = $x_min_global;	
								$old_ymin_global = $y_min_global;
								
								
								
								my $max_slice = max (@max_slice_reqs);
								print report_file "*************max_slice = $max_slice***********\n";
								
								#my $x_min_global_range = $device_max_x_range_fp-$total_H_slice_reqs-$int_frag_x;
								my $x_min_global_range = $device_max_x_range_fp - sqrt($max_slice) -$int_frag_x;
								
								$x_min_global = int( rand($x_min_global_range) );
								if ($x_min_global < 0){
									
									$x_min_global = 0;
								}
								
								print (report_file "*************** x_min_global = $x_min_global x_min_global_range in starting loc change = $x_min_global_range **************************\n");
								print (report_file "*************** device_max_x_range_fp = $device_max_x_range_fp,  total_H_slice_reqs= $total_H_slice_reqs, int_frag = $int_frag_x **************************\n");
								
								my $temp_size = @module_list_test; # number of modules to multiply with int_frag_y
								 
								 
								
								my $y_min_global_range = $device_max_y_range_fp-$total_V_slice_reqs- ($temp_size*$int_frag_y);
								
								
								#my $y_min_global_range = $device_max_y_range_fp- sqrt($max_slice) -$int_frag_y;
								
								$y_min_global = int( rand($y_min_global_range) );
								
								
								if ($y_min_global < 0){
									
									$y_min_global = 0;
								}

								print (report_file "*************** y_min_global = $y_min_global y_min_global_range in starting loc change = $y_min_global **************************\n");
								print (report_file "*************** device_max_y_range_fp = $device_max_y_range_fp,  total_V_slice_reqs= $total_V_slice_reqs, int_frag = $int_frag_y **************************\n");
																
								print report_file "x_min_global_final = $x_min_global\n";
								print report_file "y_min_global_final = $y_min_global\n";
								$x_max_global = 0;
								
								
								
								
								return  1;
							}
							######################Change starting location##########################
						}    ########end case
					}
				print "#################iteration = $iteration #############################\n";
#################floorplan intial solution and calculate clock frequency#####################
				
				write_constraints();

				sub write_constraints {
					my $lp = 0;

					
					#print report_file "place_contraints_module = @place_contraints_module\n";
					foreach my $module_name (@place_contraints_module) {
						print OUTFILE_dcf ("# @E0 \n");
						print OUTFILE_dcf ("# Iteration = $iteration Rand_iter = $rand_iter \n");
						print OUTFILE_dcf ("INST \"$module_name\" AREA_GROUP = \"pblock_$module_name\";\n");
						print OUTFILE_dcf ( "AREA_GROUP \"pblock_$module_name\" RANGE=SLICE_X$placement_contraints_X_min[$lp]",
"Y$placement_contraints_Y_min[$lp]:SLICE_X$placement_contraints_X_max[$lp]",
							"Y$placement_contraints_Y_max[$lp];\n"
						);
						$lp++;
					}
				
					
				}
			
				#rand_clk_entry_test();    #########generates random clocks for testing purposes
			
					write_ucf(); # copies ucf from main directory and copies dcf contents into a ucf file
					copy_fp();
					implement(); #############implement the design
					
					if($PAR_error_flag==1){
						return;	
					}
					
					design_evaluation(); 
				
					
		
				###############################################
#################calculate average cost of placements#########################
				
				if ($iteration == ($rand_iter-1)){
					average_cost_test();
					@E0_SA = @E_orig;
					@BEST_FP  = @E0_SA;
					$BEST_FP_ITER = $iteration;
					print report_file "E0_SA = @E0_SA, ";
					print report_file "BEST_FP = @BEST_FP,  ";
					print report_file "BEST_FP_ITER = $BEST_FP_ITER\n";
					
					
					$x_min = 0;
					$x_min_global = 0; #this is used to intialize the starting postion of the floorplanner
					$y_min = 0;
					$x_max = 0;
					$x_max_global = 0; # this is used so that adjacent modules dont overlap with slicing floorplanning
					$y_max = 0;
					$y_min_global = 0;
					$x_min_last = 0;
					$y_min_last = 0;
					$x_max_last = 0;
					$y_max_last = 0;
					
					$old_xmin_global = 0;
					$old_xmax_global = 0;
					$old_ymax_global = 0;
					$old_ymin_global = 0;
					
					
					
				}
				sub average_cost_test {
					my $counter    = 0;
					my $sum        = 0;
					print "@clock_frequency_list\n";
					my $temp_clock = $clock_frequency_list[0];
					foreach my $clk (@clock_frequency_list) {
						my $temp_val = $temp_clock - $clk;
						if ( $temp_val > 0 ) {    #uphill move
							$sum += $temp_val;
							$counter++;
							$temp_clock = $clk;
							print "UPHILL Move\n";
						}
						else {
							$temp_clock = $clk;
							print "Downhill or Static Move\n";
							#print( "Calculating average cost iteration no=$iteration rand_iter=$rand_iter\n" );
						}
					}
					if ( $counter != 0 ) {
						$average_cost = ( $sum / $counter );
						if ( $average_cost == 0 ) {
							$average_cost = 1;
						}
						$T_initial = ( -$average_cost / log($P_accept) );
						$Temperature = $T_initial;
						print( report_file"\nXXXXXXXXXXXXXXXXXXXXX avg cost = $average_cost, T_initial = $T_initial XXXXXXXXXXXXXXXXXXXXXX\n");
					    print("XXXXXXXXXXXXXXXXXXXXX avg cost = $average_cost, T_initial = $T_initial XXXXXXXXXXXXXXXXXXXXXX\n");
					}
					else {
						if ( $average_cost == 0 ) {
							$average_cost = 10;
						}
						$T_initial = -( $average_cost / log($P_accept) );
						$Temperature = $T_initial;
					}
				}
################ begin solution placement################
###################################################
			}

			}
			sub SA_PRR_algorithm {
				my $random = rand;
				my $cost_change;
				
			    #$Temperature = $T_initial;#########intialized during average cost calculation
				
				#############initialized during variable declarations###########
				#$MT          = 0;
				#$uphill      = 0;
				#$Reject      = 0;
				#############initialized during variable declarations###########
				
				
						
					###################three types of  perturbation performed#####################
				
					my $M=3;
					my $temp_size = @E0;
			
					print "ts =  $temp_size \n";
					if ($temp_size <= 3){
					
					 $M = 2;
					 print("####################Swap Move cancelled###################\n");	
					
					}
					
					##############change starting location every 5 iterations###################
					
					my $permutation = 2*$N;
					
					if ($iteration % $permutation == 0){
						$Move = 0; 
						print report_file "Permutation value = $permutation Starting location changed\n";
					##############change starting location every 5 iterations###################
					}else{
						$Move = int( rand($M) ) + 1;	
					}
					
					
					my $ret_value;
					###########create placements##########
					
					print report_file "Simulated Annealing placement for iteration = $iteration, Move = $Move \n";
					perturbation($Move);
					$ret_value = PRR_placement();
					
					
					while ($ret_value == 0){
						my $pert_ret_value = perturbation($Move);
						if($pert_ret_value == 0){
							$Move = int( rand(2) ) + 1;
						}
						else{
							$Move = int( rand($M) ) + 1;	
						}
						$ret_value = PRR_placement();
						
						#$Move = 4;
						print report_file "Move value = $Move\n";
						print report_file "PRR placement return value = $ret_value\n";
					}
					
					
						
						#############end create placements################
							
						
						
					#	perturbation ($Move); #perform pertubation 
					#	PRR_placement(); #create new flooplan


					#	rand_clk_entry_test();    #########generates random clocks for testing purposes
						
						
					write_constraints();
					write_ucf(); # copies ucf from main directory and copies dcf contents into a ucf file
					copy_fp();	
					implement(); #############implement the design
					
					if($PAR_error_flag==1){
						return;	
					}
					
					design_evaluation(); 
								
						
						
											
						
						$MT=$MT+1;
						
						
						
						print "iteration = $iteration\n";
						print "@clock_frequency_list\n";
					
						$cost_change = ((1/ $clock_frequency_list [$iteration-1]) - (1/ $clock_frequency_list[$iteration-2] ) );
						$cost_change = $cost_change * 10000;
						my $acceptance_probability = exp( - ($cost_change/$Temperature)) ;
						
						
						print report_file "cost_change = $cost_change\n";
						print report_file "random = $random\n";
						print report_file "Temperature = $Temperature\n";
						print report_file " exp(-(cost_change/Temperature) = $acceptance_probability\n";
						
						if ($cost_change <= 0 or $random < $acceptance_probability) {
							
							if($cost_change > 0){
							
								$uphill =$uphill +1;
								print report_file "uphill = $uphill"; 
								#new floorplan already accepted	as E0 is updated during floorplan pertubation
							} #end if
							if ($clock_frequency_list [$iteration - 1] > $clock_frequency_list [$BEST_FP_ITER]){
								
								print report_file "clock_frequency_list [iteration - 1] > clock_frequency_list [BEST_FP_ITER]";
								$BEST_FP_ITER = $iteration;
								@BEST_FP = @E0;
							} 
							else{
								$Reject = $Reject +1;
								print report_file "floorplan rejected restore E0 = @E0 to original value E0_SA = @E0_SA";
								#restore starting location constraints to previous one
								$x_min_global = $old_xmin_global;	
								$y_min_global = $old_ymin_global;
								#restore starting location constraints to previous one
								@E0 = @E0_SA;	#floorplan rejected restore @E0 to original value
								
								create_fp_stack; #recreate stack
							} #end if
							
						} #end if
						
						if ($uphill > $N or ($MT > 2*$N)){
							print report_file "uphill > N $uphill > $N or MT > 2*N $MT > 2*$N \n ";
							print report_file "Temperature reduced from $Temperature to ";
							$Temperature = $Temperature * $T_reduction_rate;
							print report_file "$Temperature\n";
							$MT          = 1;
							$uphill      = 0;
							$Reject      = 0;
						}#end if
						print "E0_SA = @E0_SA, ";
						print "BEST_FP = @BEST_FP,  ";
						print "BEST_FP_ITER = $BEST_FP_ITER\n";	
						print report_file "E0_SA = @E0_SA, ";
						print report_file "BEST_FP = @BEST_FP,  ";
						print report_file "BEST_FP_ITER = $BEST_FP_ITER\n";	
				  
			}
##########################################SA_END##########################
			


				close(OUT);    #this closes is for V4LX25lib output file handle
######write dcf and copy to ucf################
				sub write_ucf {
					open( INF, "<$infilename.ucf" );
					print OUTFILE_dcf ( "
#####################################################################################
## Constraints from file : 'top.ucf' 
####################################ucf_start########################################\n"
					);
					my $temp_flag = $DAPR_flag_ucf;
					foreach my $line (<INF>) {
						if ( $temp_flag == 1 ) {
							if ( $line !~ /ucf_start/ ) {
								next;
							}
							else {
								$temp_flag = 0;
							}
						}
						else {
							print OUTFILE_dcf ($line);
						}
					}
					system(
"cp ./PR_Automated/design$iteration/top.dcf ./PR_Automated/design$iteration/top.ucf"
					);

					#close(OUTFILE_dcf);
				}

				#############SUBROUTINE for writing Partion Pin contraints
#####################Simulated annealing algorihtm for bus macro/partition pin placements starts here#############################################

############################################
		}
	}
}
########################### XILINX SYNTHESIS #########################
sub xst {

	#Autoscript generation for xst
	
	PRM_syn();
	Base_syn();
	top_syn();
	
	
####################top file synthesizing##################################################
	sub top_syn {
		my $format  = "ngc";
		my $format1 = "NGC";
		mkdir("PR_Automated/synth/$infilename");
		system("cp $infilename.ucf PR_Automated/synth/$infilename/");
		system("cp $infilename.vhd PR_Automated/synth/$infilename/");
		open( OUTFILE, ">PR_Automated/synth/$infilename/$infilename.script" )
		  or die "Cannot open output file!";
		print OUTFILE "run
-ifn ./$infilename.vhd
-ifmt VHDL
-ofn $infilename.$format
-ent $Top_entity_list
-ofmt $format1
-p $device_name
-top $Top_entity_list
-opt_mode Area
-opt_level 2
-power NO
-iuc NO
-keep_hierarchy YES
-netlist_hierarchy as_optimized
-rtlview Yes
-glob_opt AllClockNets
-read_cores YES
-write_timing_constraints NO
-cross_clock_analysis NO
-hierarchy_separator /
-bus_delimiter <>
-case maintain
-slice_utilization_ratio 100
-bram_utilization_ratio 100
-dsp_utilization_ratio 100
-verilog2001 YES
-fsm_extract YES -fsm_encoding Auto
-safe_implementation No
-fsm_style lut
-ram_extract Yes
-ram_style Auto
-rom_extract Yes
-mux_style Auto
-decoder_extract YES
-priority_extract YES
-shreg_extract YES
-shift_extract YES
-xor_collapse YES
-rom_style Auto
-auto_bram_packing NO
-mux_extract YES
-resource_sharing YES
-async_to_sync NO
-use_dsp48 auto
-iobuf YES
-max_fanout 500
-bufg 32
-bufr 24
-register_duplication YES
-register_balancing No
-slice_packing YES
-optimize_primitives NO
-use_clock_enable Auto
-use_sync_set Auto
-use_sync_reset Auto
-iob auto
-equivalent_register_removal YES
-slice_utilization_ratio_maxmargin 5
";
		close(OUTFILE);
		chdir("./PR_Automated/synth/$infilename")
		  || die "Error!! Could not change Directory.";
		system("xst -ifn ./$infilename.script -intstyle ise");
		reset_dir();
		push( @region_instance, $Top_entity_list );    #for overlay gen
		slice_requirement_finder( $infilename, $Top_entity_list );

#system ("cp PR_Automated/synth/$infilename/$infilename.ngc PR_Automated/top/");
#system ("cp PR_Automated/synth/$infilename/$infilename.edn PR_Automated/top/");
#############xst -ifn in_file_name -ofn out_file_name -intstyle {silent|ise|xflow}#############
		#	system("ngc2edif $infilename.ngc $infilename.edn");
	}
	print report_file
	  "------------------------------------------------------\n";

	sub PR_script_generation {
		my $format    = "ngc";
		my $format1   = "NGC";
		
		my $filename1 = $_[0];
		my $filename2 = $_[1];
		#print "@_\n";
		#print "script $_[0] $filename1\n";
		#print "script $_[1] $filename2\n";
		chomp($filename1);
		chomp($filename2);
		open( OUTFILE, ">PR_Automated/synth/$filename1/$filename1.script" )
		  or die "Cannot open output file!";
		print OUTFILE "run
-ifn ./$filename1.vhd
-ifmt VHDL
-ofn $filename2.$format
-ent $filename2
-ofmt $format1
-p $device_name
-top $filename2
-opt_mode Area
-opt_level 2
-power NO
-iuc NO
-keep_hierarchy YES
-netlist_hierarchy as_optimized
-rtlview Yes
-glob_opt AllClockNets
-read_cores YES
-write_timing_constraints NO
-cross_clock_analysis NO
-hierarchy_separator /
-bus_delimiter <>
-case maintain
-slice_utilization_ratio 100
-bram_utilization_ratio 100
-dsp_utilization_ratio 100
-verilog2001 YES
-fsm_extract YES -fsm_encoding Auto
-safe_implementation No
-fsm_style lut
-ram_extract Yes
-ram_style Auto
-rom_extract Yes
-mux_style Auto
-decoder_extract YES
-priority_extract YES
-shreg_extract YES
-shift_extract YES
-xor_collapse YES
-rom_style Auto
-auto_bram_packing NO
-mux_extract YES
-resource_sharing YES
-async_to_sync NO
-use_dsp48 auto
-iobuf NO
-max_fanout 500
-bufg 32
-bufr 24
-register_duplication YES
-register_balancing No
-slice_packing YES
-optimize_primitives NO
-use_clock_enable Auto
-use_sync_set Auto
-use_sync_reset Auto
-iob auto
-equivalent_register_removal YES
-slice_utilization_ratio_maxmargin 5
";
		close(OUTFILE);
		return;
	}
##############PRM SYNTHESIZING START###########################################
	sub PRM_syn {
		my $count                = 0;
		my $module_count         = 0;
		my @temp_PR_module_count = @PR_module_count;
		#print "temp_PR_module_count = @temp_PR_module_count\n";
		if ( $PR_flag_syn == 1 ) {
			for ( $count = 0 ; $count < @PR_file_list ; $count++ ) {
				mkdir("PR_Automated/synth/$PR_file_list[$count]");

				#	mkdir ("PR_Automated/reconfigmodules/$PR_file_list[$count]");
				system("cp $PR_file_list[$count].vhd PR_Automated/synth/$PR_file_list[$count]/" );
                
                    
                system("cp $PR_file_list_ngc[$count].ngc PR_Automated/synth/$PR_file_list[$count]/");
				
				if ( $temp_PR_module_count[$count] > 0 ) {
					$temp_PR_module_count[$module_count]--;
				}
				else {
					$module_count++;
				}
#				print "count = $count\n";
#				print "module_count = $module_count\n";
#				print "PR_FILE_LIST = $PR_file_list[$count]\n";
#				print "PR_component_list = $PR_component_list[$count]\n";
				PR_script_generation( $PR_file_list[$count],
									  $PR_component_list[$count] );
				chdir("./PR_Automated/synth/$PR_file_list[$count]")
				  || die "Error!! Could not change Directory.";
				
				#print (report_file "xst -ifn ./$PR_file_list[$count].script -intstyle ise\n");
				system("xst -ifn ./$PR_file_list[$count].script -intstyle ise");

#			system("ngc2edif $PR_component_list[$module_count].ngc $PR_component_list[$module_count].edn");
				reset_dir();

#	system ("cp PR_Automated/synth/$PR_file_list[$count]/$PR_component_list[$module_count].ngc PR_Automated/reconfigmodules/$PR_file_list[$count]/");
#	system ("cp PR_Automated/synth/$PR_file_list[$count]/$PR_component_list[$module_count].edn PR_Automated/reconfigmodules/$PR_file_list[$count]/");
				slice_requirement_finder( $PR_file_list[$count], $PR_component_list[$count] );
				push( @region_instance, $PR_module_list[$count] )
				  ;    #for overlay gen
			}
		}
		else {
			print "No PR Regions Found\n\n";
			close(report_file);
		}
	}

	#PRM SYNTEHSIZING END
###########BASE SYNTHESIZING START################
	sub Base_syn {
		my $format  = "ngc";
		my $format1 = "NGC";
		for ( my $count = 0 ; $count < @Base_file_list ; $count++ ) {
			system("mkdir PR_Automated/synth/$Base_file_list[$count]");
			system(
"cp $Base_file_list[$count].vhd PR_Automated/synth/$Base_file_list[$count]/" );
			open( OUTFILE,
">PR_Automated/synth/$Base_file_list[$count]/$Base_file_list[$count].script"
			) or die "Cannot open output file!";
			print OUTFILE "run
-ifn ./$Base_file_list[$count].vhd
-ifmt VHDL
-ofn $Base_component_list[$count].$format
-ent $Base_component_list[$count]
-ofmt $format1
-p $device_name
-top $Base_component_list[$count]
-opt_mode Area
-opt_level 2
-power NO
-iuc NO
-keep_hierarchy YES
-netlist_hierarchy as_optimized
-rtlview Yes
-glob_opt AllClockNets
-read_cores YES
-write_timing_constraints NO
-cross_clock_analysis NO
-hierarchy_separator /
-bus_delimiter <>
-case maintain
-slice_utilization_ratio 100
-bram_utilization_ratio 100
-dsp_utilization_ratio 100
-verilog2001 YES
-fsm_extract YES -fsm_encoding Auto
-safe_implementation No
-fsm_style lut
-ram_extract Yes
-ram_style Auto
-rom_extract Yes
-mux_style Auto
-decoder_extract YES
-priority_extract YES
-shreg_extract YES
-shift_extract YES
-xor_collapse YES
-rom_style Auto
-auto_bram_packing NO
-mux_extract YES
-resource_sharing YES
-async_to_sync NO
-use_dsp48 auto
-iobuf NO
-max_fanout 500
-bufg 32
-bufr 24
-register_duplication YES
-register_balancing No
-slice_packing YES
-optimize_primitives NO
-use_clock_enable Auto
-use_sync_set Auto
-use_sync_reset Auto
-iob auto
-equivalent_register_removal YES
-slice_utilization_ratio_maxmargin 5
";
			close(OUTFILE);
			chdir("./PR_Automated/synth/$Base_file_list[$count]")
			  || die "Error!! Could not change Directory.";
			system("xst -ifn ./$Base_file_list[$count].script -intstyle ise ");

#		system("ngc2edif $Base_component_list[$count].ngc $Base_component_list[$count].edn");
			reset_dir();

#	system ("cp PR_Automated/synth/$Base_file_list[$count]/$Base_component_list[$count].ngc PR_Automated/base/");
#			system ("cp PR_Automated/synth/$Base_file_list[$count]/$Base_component_list[$count].edn PR_Automated/base/");
			slice_requirement_finder( $Base_file_list[$count],
									  $Base_component_list[$count] );
			push( @region_instance, $Base_module_list[$count] )
			  ;    #for overlay gen
		}
	}
#################BASE Synthesizing END###################################
#########################FIND MAX resource requirements of each PRR after synthesis#####################
	my $lp = 0;    # PRR loop counter
	our $pp_lp = 0;    # Partition Pin loop counter


	foreach my $PRR (@PR_module_list) {
		$PRR =~ s/\s+//g;
		#print "\n PRR= $PRR\n";
		my $lp0 = 0;
		## find max slice requirements for each PRR and write to appropriate array
		foreach my $cmp (@region_instance) {
			$cmp =~ s/\s+//g;
			if ( $cmp eq $PRR ) {
				#if ( $max_slice_reqs[$lp] < $module_slice_requirement[$lp0] ) {
					$max_slice_reqs[$lp] = $module_slice_requirement[$lp0];
				#}
			}
			$lp0++;
		}
		push( @module_list_fp, $PRR );

		#	print(" Region $PRR max slice_reqs = $max_slice_reqs[$lp]\n");
		$lp++;
	}




########################FIND MAX resource requirements of each PRR after synthesis#####################
	foreach my $static (@Base_module_list) {
		$static =~ s/\s+//g;
		#print "\nBase= $static\n";
		my $lp0 = 0;
		## find max slice requirements for each static region and write to appropriate array
		foreach my $cmp (@region_instance) {
			$cmp =~ s/\s+//g;
			if ( $cmp eq $static ) {
				push( @max_slice_reqs, $module_slice_requirement[$lp0] );
			}
			$lp0++;
		}
		push( @module_list_fp, $static );

		#	print(" Region $static max slice_reqs = $max_slice_reqs[$lp]\n");
	}
}

#}
###END SYNTHESIZING-----------------------------------------------------------------------------------------------------------------------------------------------
sub clean_up {
	if ( -d "PR_Automated" ) {
		system("rm -R PR_Automated");
	}
	system(
"rm -rf *.ngd *.bld *.mrp *.ncd *.ngm *.pad.* *.par *.twr *.bit *.drc *.bgn *.xrpt *.twx *.ptwx *.ise *.lso *.script *.dcf *.dil"
	);
	system(
"rm -rf *.pcf *.png *.xpi  *vhdl.prj *pad.txt  *.pad *.srp *pad.csv *.map *.ngr netlist.lst xst xlnx_auto_0_xdb"
	);
	system("rm -rf *~ *.v *.sdf *.bin *.txt");
	system("rm -rf *.grf *.nlf *.msk *.unroutes *.xml *.log");
	system("rm -rf *.prai");
	mkdir("PR_Automated");

	#chmod -R "PR_Automated";
	mkdir("PR_Automated/synth");

	#	mkdir("PR_Automated/synth/macros");
	#mkdir ("PR_Automated/base");
	#	mkdir ("PR_Automated/merges");
	#	mkdir ("PR_Automated/reconfigmodules");
	#	mkdir ("PR_Automated/top");
}

sub slice_requirement_finder {
	my $filename1 = $_[0];
	my $filename2 = $_[1];
	chomp($filename1);
	chomp($filename2);

#	open (OUTFILE, ">PR_Automated/synth/$filename1/$filename1.script") or die "Cannot open output file!";
	my $Slices = 0;
	my $i;
	open( INFILE_srp, "<./PR_Automated/synth/$filename1/$filename1.srp" )
	  or die "SRP file can not be opened!";
	#print report_file "***** $filename1 $filename2 \n";
	while ( my $line = <INFILE_srp> ) {
		next if ( $line !~ /Number of Slices:/i );
		if ( $line =~ /Number of Slices:/i ) {
			my @list = split( ' ', $line );
			$Slices = $list[3];
			push( @module_list,              $filename1 );
			push( @region_list,              $filename2 );
			push( @module_slice_requirement, $Slices );
			print report_file
			  "$filename1:$filename2 slice requirement = $Slices\n";
		}
	}
	close(INFILE_srp);
}
print("############Operations Complete Successfully!!!#######################");

#xst();
#implement();
#print "par -intstyle ise $infilename.ncd -w $infilename\_routed.ncd\n";
sub implement {

	#	$iteration = 1;
	NGD_BUILD();
	MAP_PAR();
	BITGEN();

	sub NGD_BUILD {
		#######copy_top_ngcs
		#mkdir("./PR_Automated/design$iteration");
		system(
"cp PR_Automated/synth/$infilename/*.ngc PR_Automated/design$iteration/" );
		#######copy_base_ngcs
		for ( my $count = 0 ; $count < @Base_file_list ; $count++ ) {
			system(
"cp PR_Automated/synth/$Base_file_list[$count]/$Base_component_list[$count].ngc PR_Automated/design$iteration"
			);
		}
		#########copy_PRR_ngcs
		foreach my $filename (@PR_file_list) {
			system(
"cp PR_Automated/synth/$filename/*.ngc PR_Automated/design$iteration/" );
		}
		################
#
#		chdir("./PR_Automated/design$iteration/$infilename/")
#		  || die "Error!! Could not change Directory.";
#system("ngdbuild -quiet -intstyle ise -modular initial -uc $infilename.ucf $infilename.ngc");#ise 9.2
#print "\nXXXXXXXXXXXXxngd_build_path = $ngd_build_path\n";
		reset_dir();
		chdir("./PR_Automated/design$iteration")
		  || die "Error!! Could not change Directory.";
		system( "ngdbuild -intstyle ise -p $device_name -uc $infilename.ucf $infilename.ngc" );

		print report_file "ngdbuild -intstyle ise -p $device_name -uc $infilename.ucf $infilename.ngc\n" ;


		open( INFILE_BLD, "<$infilename.bld" ) || die "Cannot open BLD file";
		
		while ( my $line = <INFILE_BLD> ) {
			chomp($line);
			next if ( $line !~ /Number of errors:/i );
			$line =~ s/(\D+)//g;
			print report_file
			  "\n\nBLD errors for iteration $iteration $infilename= $line\n";
			if ( $line != 0 ) {

				#$iter=0;
				reset_dir();
				chdir("./PR_Automated/") || die "could not change directory!";
				system "rm -R design$iteration" || die "directory not removed!";
				$PAR_error_count++;
				$PAR_error_flag = 1;
				print( report_file
					   "\nXXXEntering BLD error setting flag=$PAR_error_flag\n"
				);
				reset_dir();
				return;
				print( report_file "\nXXXEntering BLD error setting?????\n" );
			}
		}
		reset_dir();
	}
	reset_dir();

	
	sub MAP_PAR {
		chdir("./PR_Automated/design$iteration")
		  || die "Error!! Could not change Directory.";
		system("map -intstyle ise -w $infilename.ngd");
		print report_file "map -intstyle ise -w $infilename.ngd\n" ;
		
		open( INFILE_MRP, "<$infilename.mrp" ) || die "Cannot open mrp file";
		while ( my $line = <INFILE_MRP> ) {
			chomp($line);
			next if ( $line !~ /Number of errors:/i );

			#					print ("\nXXXXXXX $line XXXXXXXXX\n");
			$line =~ s/(\D+)//g;
			print report_file
			  "\n\nMAP errors for iteration $iteration $infilename= $line\n";
			if ( $line != 0 ) {

				#$iter=0;
				reset_dir();
				chdir("./PR_Automated/") || die "could not change directory!";
				system "rm -R design$iteration" || die "directory not removed!";
				$PAR_error_count++;
				$PAR_error_flag = 1;
				print( report_file
					   "\nXXXEntering MAP error setting flag=$PAR_error_flag\n"
				);
				reset_dir();
				return;
				print( report_file "\nXXXEnterin MAP error setting?????\n" );
			}
		}
		system(
			  "par -intstyle ise $infilename.ncd -w $infilename\_routed.ncd\n");
		open( INFILE_PAR, "<$infilename\_routed.par" )
		  || die "Cannot open PAR file";
		while ( my $line = <INFILE_PAR> ) {
			chomp($line);
			next if ( $line !~ /Number of error messages:/i );

			#					print ("\nXXXXXXX $line XXXXXXXXX\n");
			$line =~ s/(\D+)//g;
			print report_file
			  "\n\nPAR errors for iteration $iteration  static= $line\n";
			if ( $line != 0 ) {

				#$iter=0;
				reset_dir();
				chdir("./PR_Automated/") || die "could not change directory!";
				system "rm -R design$iteration" || die "directory not removed!";
				$PAR_error_count++;
				$PAR_error_flag = 1;
				print( report_file
					  "\nXXXEnterin PAR error setting flag=$PAR_error_flag\n" );
				reset_dir();
				return;
				print( report_file "\nXXXEnterin PAR error setting?????\n" );
			}
		}
		reset_dir();
	}

#*****************End implementation phase*************************************************************
	sub BITGEN {
		chdir("./PR_Automated/design$iteration")
		  || die "Error!! Could not change Directory.";

#system("xdl -secure -ncd2xdl -nopips $infilename\_routed.ncd $infilename\_routed.xdl");
		system("bitgen $infilename\_routed.ncd $infilename\_routed.bit $infilename.pcf -w -intstyle ise"
		);
		#system("bitgen -r $infilename\_routed.bit $infilename\_routed.ncd partial.bit"); #generate partial bit file

#	print (report_file "PR_assemble static.ncd @temp_PR_file_list_initial\n***********************************");
		reset_dir();
		mkdir("./PR_Automated/design$iteration/bitstreams");
		system(
"cp ./PR_Automated/design$iteration/*.bit ./PR_Automated/design$iteration/bitstreams"
		);
		reset_dir();
	}
}

#*****************End merge phase*************************************************************
########################design evaluation phase########################################
sub design_evaluation {
	push( @design_iteration, $iteration );
	print( RESULTS_iter "$iteration\n" );
	chdir("./PR_Automated/design$iteration/");
	system("trce -u -a top_routed.ncd");

	open( INFILE_trce, "<./top_routed.twr" )
	  or die "TWR file can not be opened!";
	while ( my $line = <INFILE_trce> ) {
		chomp($line);
		next if ( $line !~ /Maximum frequency:/i );
		$line =~ s/\s+//g;
		my @list = split( /frequency:/i, $line );
		$list[1] =~ s/\D+//g;
		$list[1] = $list[1] / 1000;
		push( @clock_frequency_list, $list[1] );
		print( RESULTS_clk "$list[1]\n" );
	}
	reset_dir();
	#chdir("./PR_Automated/design$iteration/bitstreams");
	#my $partial_bs_filename = "$PR_file_list[0]_partial.bit";
	#my $Partial_bs_size     = -s $partial_bs_filename;
	#my $partial_bs_filename = "partial.bit";
	#my $Partial_bs_size     = -s $partial_bs_filename;
	#$Partial_bs_size = $Partial_bs_size / 1000;
#	print( RESULTS_bs_size "$Partial_bs_size\n" );


################check for report_file size

	my $rs_filename = "report_file.log";
	my $rs_filename_size     = -s $rs_filename;
	#my $partial_bs_filename = "partial.bit";
	#my $Partial_bs_size     = -s $partial_bs_filename;
	print report_file "report file size $rs_filename_size bytes\n";
    if ($rs_filename_size > 1000000000 ){
    	
    	exit;	
    	
    }

############################################

	#	push  (@PRR_size, $internal_PAR_Flag);
	#	print (RESULTS_PRR_size "$internal_PAR_Flag\n");
	reset_dir();
}
########################end design evaluation phase########################################
#****************************************************Copy ucf**************
sub copy_fp {
	reset_dir();
	open( INF, "<./PR_Automated/design$iteration/$infilename.ucf" );
	print RESULTS_FP ( "
#####################################################################################
## Start of Design$iteration Constraints file : 'top.ucf' 
####################################ucf_start########################################\n"
	);

	#my $temp_flag=$DAPR_flag;
	foreach my $line (<INF>) {
		print RESULTS_FP ($line);

		# if($temp_flag==1){
		#if($line !~ /ucf_start/){
		#next;
		#}
		#else{
		#$temp_flag=0;
		#}
		#}
		#else{
		#}
	}

#system ("cp ./PR_Automated/design$iteration/top.dcf ./PR_Automated/design$iteration/top.ucf");
	print RESULTS_FP ( "
#####################################################################################
## End of Design$iteration Constraints file : 'top.ucf' 
####################################ucf_start########################################\n"
	);

	#close(OUTFILE_dcf);
}

sub del_design {
	reset_dir();
	chdir("./PR_Automated/") || die "could not change directory!";
	system "rm -R design$iteration" || die "directory not removed!";

   #$PAR_error_count++;
   #$PAR_error_flag=1;
   #print(report_file "\nXXXEntering BLD error setting flag=$PAR_error_flag\n");
	reset_dir();
}

#recursive subroutine to find the nth factorial########
sub fac {
	my ($n) = @_;
	if ( $n < 2 ) {
		return $n;
	}
	else {
		return $n * fac( $n - 1 );
	}
}
#####################generate random clock for testing purposes################
#rand_clk_entry_test();
sub rand_clk_entry_test {
	my $rand_clk;
	my $clk_rand_range = 50;
	$rand_clk = int( rand($clk_rand_range) ) + 200;
	push( @clock_frequency_list, $rand_clk );

	#print("\nnew clock=$rand_clk\Mhz\n");
}
#####################end random clock for testing purposes################
# end recursive subroutine to find the nth factorial########
